diff options
Diffstat (limited to 'drivers/media/video/saa7134')
-rw-r--r-- | drivers/media/video/saa7134/Kconfig | 68 | ||||
-rw-r--r-- | drivers/media/video/saa7134/Makefile | 9 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa6752hs.c | 187 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-alsa.c | 1047 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-cards.c | 587 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-core.c | 120 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-dvb.c | 370 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-empress.c | 6 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-i2c.c | 28 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-input.c | 403 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-oss.c | 375 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-reg.h | 27 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-ts.c | 29 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-tvaudio.c | 23 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-video.c | 185 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134.h | 62 |
16 files changed, 3013 insertions, 513 deletions
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig new file mode 100644 index 000000000000..624e8808a517 --- /dev/null +++ b/drivers/media/video/saa7134/Kconfig @@ -0,0 +1,68 @@ +config VIDEO_SAA7134 + tristate "Philips SAA7134 support" + depends on VIDEO_DEV && PCI && I2C && SOUND + select VIDEO_BUF + select VIDEO_IR + select VIDEO_TUNER + select CRC32 + ---help--- + This is a video4linux driver for Philips SAA713x based + TV cards. + + To compile this driver as a module, choose M here: the + module will be called saa7134. + +config VIDEO_SAA7134_DVB + tristate "DVB/ATSC Support for saa7134 based TV cards" + depends on VIDEO_SAA7134 && DVB_CORE + select VIDEO_BUF_DVB + ---help--- + This adds support for DVB cards based on the + Philips saa7134 chip. + + To compile this driver as a module, choose M here: the + module will be called saa7134-dvb. + + You must also select one or more DVB demodulators. + If you are unsure which you need, choose all of them. + +config VIDEO_SAA7134_DVB_ALL_FRONTENDS + bool "Build all supported frontends for saa7134 based TV cards" + default y + depends on VIDEO_SAA7134_DVB + select DVB_MT352 + select DVB_TDA1004X + select DVB_NXT200X + ---help--- + This builds saa7134-dvb with all currently supported frontend + demodulators. If you wish to tweak your configuration, and + only include support for the hardware that you need, choose N here. + + If you are unsure, choose Y. + +config VIDEO_SAA7134_DVB_MT352 + tristate "Zarlink MT352 DVB-T Support" + default m + depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS + select DVB_MT352 + ---help--- + This adds DVB-T support for cards based on the + Philips saa7134 chip and the MT352 demodulator. + +config VIDEO_SAA7134_DVB_TDA1004X + tristate "Phillips TDA10045H/TDA10046H DVB-T Support" + default m + depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS + select DVB_TDA1004X + ---help--- + This adds DVB-T support for cards based on the + Philips saa7134 chip and the TDA10045H/TDA10046H demodulator. + +config VIDEO_SAA7134_DVB_NXT200X + tristate "NXT2002/NXT2004 ATSC Support" + default m + depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS + select DVB_NXT200X + ---help--- + This adds ATSC 8VSB and QAM64/256 support for cards based on the + Philips saa7134 chip and the NXT2002/NXT2004 demodulator. diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index b778ffd94e65..e0b28f0533af 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -3,15 +3,22 @@ saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \ saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o \ saa7134-vbi.o saa7134-video.o saa7134-input.o -obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa6752hs.o +obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \ + saa6752hs.o saa7134-alsa.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o EXTRA_CFLAGS += -I$(src)/.. EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends +ifneq ($(CONFIG_VIDEO_BUF_DVB),n) + EXTRA_CFLAGS += -DHAVE_VIDEO_BUF_DVB=1 +endif ifneq ($(CONFIG_DVB_MT352),n) EXTRA_CFLAGS += -DHAVE_MT352=1 endif ifneq ($(CONFIG_DVB_TDA1004X),n) EXTRA_CFLAGS += -DHAVE_TDA1004X=1 endif +ifneq ($(CONFIG_DVB_NXT200X),n) + EXTRA_CFLAGS += -DHAVE_NXT200X=1 +endif diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c index 382911c6ef22..cdd1ed9c8065 100644 --- a/drivers/media/video/saa7134/saa6752hs.c +++ b/drivers/media/video/saa7134/saa6752hs.c @@ -13,7 +13,6 @@ #include <linux/init.h> #include <linux/crc32.h> -#include <media/id.h> #define MPEG_VIDEO_TARGET_BITRATE_MAX 27000 #define MPEG_VIDEO_MAX_BITRATE_MAX 27000 @@ -57,6 +56,7 @@ struct saa6752hs_state { struct i2c_client client; struct v4l2_mpeg_compression params; enum saa6752hs_videoformat video_format; + v4l2_std_id standard; }; enum saa6752hs_command { @@ -74,58 +74,58 @@ enum saa6752hs_command { /* ---------------------------------------------------------------------- */ static u8 PAT[] = { - 0xc2, // i2c register - 0x00, // table number for encoder + 0xc2, /* i2c register */ + 0x00, /* table number for encoder */ - 0x47, // sync - 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) - 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) + 0x47, /* sync */ + 0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */ + 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */ - 0x00, // PSI pointer to start of table + 0x00, /* PSI pointer to start of table */ - 0x00, // tid(0) - 0xb0, 0x0d, // section_syntax_indicator(1), section_length(13) + 0x00, /* tid(0) */ + 0xb0, 0x0d, /* section_syntax_indicator(1), section_length(13) */ - 0x00, 0x01, // transport_stream_id(1) + 0x00, 0x01, /* transport_stream_id(1) */ - 0xc1, // version_number(0), current_next_indicator(1) + 0xc1, /* version_number(0), current_next_indicator(1) */ - 0x00, 0x00, // section_number(0), last_section_number(0) + 0x00, 0x00, /* section_number(0), last_section_number(0) */ - 0x00, 0x01, // program_number(1) + 0x00, 0x01, /* program_number(1) */ - 0xe0, 0x00, // PMT PID + 0xe0, 0x00, /* PMT PID */ - 0x00, 0x00, 0x00, 0x00 // CRC32 + 0x00, 0x00, 0x00, 0x00 /* CRC32 */ }; static u8 PMT[] = { - 0xc2, // i2c register - 0x01, // table number for encoder + 0xc2, /* i2c register */ + 0x01, /* table number for encoder */ - 0x47, // sync - 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid - 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) + 0x47, /* sync */ + 0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */ + 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */ - 0x00, // PSI pointer to start of table + 0x00, /* PSI pointer to start of table */ - 0x02, // tid(2) - 0xb0, 0x17, // section_syntax_indicator(1), section_length(23) + 0x02, /* tid(2) */ + 0xb0, 0x17, /* section_syntax_indicator(1), section_length(23) */ - 0x00, 0x01, // program_number(1) + 0x00, 0x01, /* program_number(1) */ - 0xc1, // version_number(0), current_next_indicator(1) + 0xc1, /* version_number(0), current_next_indicator(1) */ - 0x00, 0x00, // section_number(0), last_section_number(0) + 0x00, 0x00, /* section_number(0), last_section_number(0) */ - 0xe0, 0x00, // PCR_PID + 0xe0, 0x00, /* PCR_PID */ - 0xf0, 0x00, // program_info_length(0) + 0xf0, 0x00, /* program_info_length(0) */ - 0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid - 0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid + 0x02, 0xe0, 0x00, 0xf0, 0x00, /* video stream type(2), pid */ + 0x04, 0xe0, 0x00, 0xf0, 0x00, /* audio stream type(4), pid */ - 0x00, 0x00, 0x00, 0x00 // CRC32 + 0x00, 0x00, 0x00, 0x00 /* CRC32 */ }; static struct v4l2_mpeg_compression param_defaults = @@ -166,33 +166,33 @@ static int saa6752hs_chip_command(struct i2c_client* client, unsigned long timeout; int status = 0; - // execute the command + /* execute the command */ switch(command) { - case SAA6752HS_COMMAND_RESET: - buf[0] = 0x00; + case SAA6752HS_COMMAND_RESET: + buf[0] = 0x00; break; case SAA6752HS_COMMAND_STOP: - buf[0] = 0x03; + buf[0] = 0x03; break; case SAA6752HS_COMMAND_START: - buf[0] = 0x02; + buf[0] = 0x02; break; case SAA6752HS_COMMAND_PAUSE: - buf[0] = 0x04; + buf[0] = 0x04; break; case SAA6752HS_COMMAND_RECONFIGURE: buf[0] = 0x05; break; - case SAA6752HS_COMMAND_SLEEP: - buf[0] = 0x06; + case SAA6752HS_COMMAND_SLEEP: + buf[0] = 0x06; break; - case SAA6752HS_COMMAND_RECONFIGURE_FORCE: + case SAA6752HS_COMMAND_RECONFIGURE_FORCE: buf[0] = 0x07; break; @@ -200,13 +200,13 @@ static int saa6752hs_chip_command(struct i2c_client* client, return -EINVAL; } - // set it and wait for it to be so + /* set it and wait for it to be so */ i2c_master_send(client, buf, 1); timeout = jiffies + HZ * 3; for (;;) { - // get the current status + /* get the current status */ buf[0] = 0x10; - i2c_master_send(client, buf, 1); + i2c_master_send(client, buf, 1); i2c_master_recv(client, buf, 1); if (!(buf[0] & 0x20)) @@ -216,61 +216,58 @@ static int saa6752hs_chip_command(struct i2c_client* client, break; } - // wait a bit msleep(10); } - // delay a bit to let encoder settle + /* delay a bit to let encoder settle */ msleep(50); - // done - return status; + return status; } static int saa6752hs_set_bitrate(struct i2c_client* client, struct v4l2_mpeg_compression* params) { - u8 buf[3]; + u8 buf[3]; - // set the bitrate mode + /* set the bitrate mode */ buf[0] = 0x71; buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1; i2c_master_send(client, buf, 2); - // set the video bitrate + /* set the video bitrate */ if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) { - // set the target bitrate + /* set the target bitrate */ buf[0] = 0x80; buf[1] = params->vi_bitrate.target >> 8; - buf[2] = params->vi_bitrate.target & 0xff; + buf[2] = params->vi_bitrate.target & 0xff; i2c_master_send(client, buf, 3); - // set the max bitrate + /* set the max bitrate */ buf[0] = 0x81; buf[1] = params->vi_bitrate.max >> 8; - buf[2] = params->vi_bitrate.max & 0xff; + buf[2] = params->vi_bitrate.max & 0xff; i2c_master_send(client, buf, 3); } else { - // set the target bitrate (no max bitrate for CBR) - buf[0] = 0x81; + /* set the target bitrate (no max bitrate for CBR) */ + buf[0] = 0x81; buf[1] = params->vi_bitrate.target >> 8; - buf[2] = params->vi_bitrate.target & 0xff; + buf[2] = params->vi_bitrate.target & 0xff; i2c_master_send(client, buf, 3); } - // set the audio bitrate - buf[0] = 0x94; + /* set the audio bitrate */ + buf[0] = 0x94; buf[1] = (256 == params->au_bitrate.target) ? 0 : 1; i2c_master_send(client, buf, 2); - // set the total bitrate + /* set the total bitrate */ buf[0] = 0xb1; - buf[1] = params->st_bitrate.target >> 8; - buf[2] = params->st_bitrate.target & 0xff; + buf[1] = params->st_bitrate.target >> 8; + buf[2] = params->st_bitrate.target & 0xff; i2c_master_send(client, buf, 3); - // return success return 0; } @@ -376,36 +373,43 @@ static int saa6752hs_init(struct i2c_client* client) h = i2c_get_clientdata(client); - // Set video format - must be done first as it resets other settings + /* Set video format - must be done first as it resets other settings */ buf[0] = 0x41; buf[1] = h->video_format; i2c_master_send(client, buf, 2); - // set bitrate - saa6752hs_set_bitrate(client, &h->params); + /* Set number of lines in input signal */ + buf[0] = 0x40; + buf[1] = 0x00; + if (h->standard & V4L2_STD_525_60) + buf[1] = 0x01; + i2c_master_send(client, buf, 2); + + /* set bitrate */ + saa6752hs_set_bitrate(client, &h->params); - // Set GOP structure {3, 13} + /* Set GOP structure {3, 13} */ buf[0] = 0x72; buf[1] = 0x03; buf[2] = 0x0D; i2c_master_send(client,buf,3); - // Set minimum Q-scale {4} + /* Set minimum Q-scale {4} */ buf[0] = 0x82; buf[1] = 0x04; i2c_master_send(client,buf,2); - // Set maximum Q-scale {12} + /* Set maximum Q-scale {12} */ buf[0] = 0x83; buf[1] = 0x0C; i2c_master_send(client,buf,2); - // Set Output Protocol + /* Set Output Protocol */ buf[0] = 0xD0; buf[1] = 0x81; i2c_master_send(client,buf,2); - // Set video output stream format {TS} + /* Set video output stream format {TS} */ buf[0] = 0xB0; buf[1] = 0x05; i2c_master_send(client,buf,2); @@ -421,9 +425,9 @@ static int saa6752hs_init(struct i2c_client* client) localPAT[sizeof(PAT) - 1] = crc & 0xFF; /* compute PMT */ - memcpy(localPMT, PMT, sizeof(PMT)); - localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f); - localPMT[4] = h->params.ts_pid_pmt & 0xff; + memcpy(localPMT, PMT, sizeof(PMT)); + localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f); + localPMT[4] = h->params.ts_pid_pmt & 0xff; localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F); localPMT[16] = h->params.ts_pid_pcr & 0xFF; localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F); @@ -436,39 +440,39 @@ static int saa6752hs_init(struct i2c_client* client) localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF; localPMT[sizeof(PMT) - 1] = crc & 0xFF; - // Set Audio PID + /* Set Audio PID */ buf[0] = 0xC1; buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF; buf[2] = h->params.ts_pid_audio & 0xFF; i2c_master_send(client,buf,3); - // Set Video PID + /* Set Video PID */ buf[0] = 0xC0; buf[1] = (h->params.ts_pid_video >> 8) & 0xFF; buf[2] = h->params.ts_pid_video & 0xFF; i2c_master_send(client,buf,3); - // Set PCR PID + /* Set PCR PID */ buf[0] = 0xC4; buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF; buf[2] = h->params.ts_pid_pcr & 0xFF; i2c_master_send(client,buf,3); - // Send SI tables + /* Send SI tables */ i2c_master_send(client,localPAT,sizeof(PAT)); i2c_master_send(client,localPMT,sizeof(PMT)); - // mute then unmute audio. This removes buzzing artefacts + /* mute then unmute audio. This removes buzzing artefacts */ buf[0] = 0xa4; buf[1] = 1; i2c_master_send(client, buf, 2); - buf[1] = 0; + buf[1] = 0; i2c_master_send(client, buf, 2); - // start it going + /* start it going */ saa6752hs_chip_command(client, SAA6752HS_COMMAND_START); - // readout current state + /* readout current state */ buf[0] = 0xE1; buf[1] = 0xA7; buf[2] = 0xFE; @@ -477,7 +481,7 @@ static int saa6752hs_init(struct i2c_client* client) i2c_master_send(client, buf, 5); i2c_master_recv(client, buf2, 4); - // change aspect ratio + /* change aspect ratio */ buf[0] = 0xE0; buf[1] = 0xA7; buf[2] = 0xFE; @@ -498,7 +502,6 @@ static int saa6752hs_init(struct i2c_client* client) buf[8] = buf2[3]; i2c_master_send(client, buf, 9); - // return success return 0; } @@ -506,16 +509,19 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind) { struct saa6752hs_state *h; - printk("saa6752hs: chip found @ 0x%x\n", addr<<1); + printk("saa6752hs: chip found @ 0x%x\n", addr<<1); - if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL))) - return -ENOMEM; + if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL))) + return -ENOMEM; memset(h,0,sizeof(*h)); h->client = client_template; h->params = param_defaults; h->client.adapter = adap; h->client.addr = addr; + /* Assume 625 input lines */ + h->standard = 0; + i2c_set_clientdata(&h->client, h); i2c_attach_client(&h->client); return 0; @@ -545,7 +551,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) struct v4l2_mpeg_compression *params = arg; int err = 0; - switch (cmd) { + switch (cmd) { case VIDIOC_S_MPEGCOMP: if (NULL == params) { /* apply settings and start encoder */ @@ -559,7 +565,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) break; case VIDIOC_G_FMT: { - struct v4l2_format *f = arg; + struct v4l2_format *f = arg; if (h->video_format == SAA6752HS_VF_UNKNOWN) h->video_format = SAA6752HS_VF_D1; @@ -576,6 +582,9 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) saa6752hs_set_subsampling(client, f); break; } + case VIDIOC_S_STD: + h->standard = *((v4l2_std_id *) arg); + break; default: /* nothing */ break; diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c new file mode 100644 index 000000000000..4f3c42354329 --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -0,0 +1,1047 @@ +/* + * SAA713x ALSA support for V4L + * + * + * Caveats: + * - Volume doesn't work (it's always at max) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <sound/driver.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/time.h> +#include <linux/wait.h> +#include <linux/moduleparam.h> +#include <linux/module.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/pcm.h> +#include <sound/initval.h> + +#include "saa7134.h" +#include "saa7134-reg.h" + +static unsigned int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"enable debug messages [alsa]"); + +/* + * Configuration macros + */ + +/* defaults */ +#define MIXER_ADDR_TVTUNER 0 +#define MIXER_ADDR_LINE1 1 +#define MIXER_ADDR_LINE2 2 +#define MIXER_ADDR_LAST 2 + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s)."); + +#define dprintk(fmt, arg...) if (debug) \ + printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ## arg) + +/* + * Main chip structure + */ +typedef struct snd_card_saa7134 { + snd_card_t *card; + spinlock_t mixer_lock; + int mixer_volume[MIXER_ADDR_LAST+1][2]; + int capture_source[MIXER_ADDR_LAST+1][2]; + struct pci_dev *pci; + struct saa7134_dev *saadev; + + unsigned long iobase; + int irq; + + spinlock_t lock; +} snd_card_saa7134_t; + + + +/* + * PCM structure + */ + +typedef struct snd_card_saa7134_pcm { + struct saa7134_dev *saadev; + + spinlock_t lock; + unsigned int pcm_size; /* buffer size */ + unsigned int pcm_count; /* bytes per period */ + unsigned int pcm_bps; /* bytes per second */ + snd_pcm_substream_t *substream; +} snd_card_saa7134_pcm_t; + +static snd_card_t *snd_saa7134_cards[SNDRV_CARDS]; + + +/* + * saa7134 DMA audio stop + * + * Called when the capture device is released or the buffer overflows + * + * - Copied verbatim from saa7134-oss's dsp_dma_stop. Can be dropped + * if we just share dsp_dma_stop and use it here + * + */ + +static void saa7134_dma_stop(struct saa7134_dev *dev) + +{ + dev->dmasound.dma_blk = -1; + dev->dmasound.dma_running = 0; + saa7134_set_dmabits(dev); +} + +/* + * saa7134 DMA audio start + * + * Called when preparing the capture device for use + * + * - Copied verbatim from saa7134-oss's dsp_dma_start. Can be dropped + * if we just share dsp_dma_start and use it here + * + */ + +static void saa7134_dma_start(struct saa7134_dev *dev) +{ + dev->dmasound.dma_blk = 0; + dev->dmasound.dma_running = 1; + saa7134_set_dmabits(dev); +} + +/* + * saa7134 audio DMA IRQ handler + * + * Called whenever we get an SAA7134_IRQ_REPORT_DONE_RA3 interrupt + * Handles shifting between the 2 buffers, manages the read counters, + * and notifies ALSA when periods elapse + * + * - Mostly copied from saa7134-oss's saa7134_irq_oss_done. + * + */ + +void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status) +{ + int next_blk, reg = 0; + + spin_lock(&dev->slock); + if (UNSET == dev->dmasound.dma_blk) { + dprintk("irq: recording stopped\n"); + goto done; + } + if (0 != (status & 0x0f000000)) + dprintk("irq: lost %ld\n", (status >> 24) & 0x0f); + if (0 == (status & 0x10000000)) { + /* odd */ + if (0 == (dev->dmasound.dma_blk & 0x01)) + reg = SAA7134_RS_BA1(6); + } else { + /* even */ + if (1 == (dev->dmasound.dma_blk & 0x01)) + reg = SAA7134_RS_BA2(6); + } + if (0 == reg) { + dprintk("irq: field oops [%s]\n", + (status & 0x10000000) ? "even" : "odd"); + goto done; + } + + if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { + dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count, + dev->dmasound.bufsize, dev->dmasound.blocks); + snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN); + saa7134_dma_stop(dev); + goto done; + } + + /* next block addr */ + next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; + saa_writel(reg,next_blk * dev->dmasound.blksize); + if (debug > 2) + dprintk("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n", + (status & 0x10000000) ? "even" : "odd ", next_blk, + next_blk * dev->dmasound.blksize, dev->dmasound.blocks, dev->dmasound.blksize, dev->dmasound.read_count); + + /* update status & wake waiting readers */ + dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks; + dev->dmasound.read_count += dev->dmasound.blksize; + + dev->dmasound.recording_on = reg; + + if (dev->dmasound.read_count >= snd_pcm_lib_period_bytes(dev->dmasound.substream)) { + spin_unlock(&dev->slock); + snd_pcm_period_elapsed(dev->dmasound.substream); + spin_lock(&dev->slock); + } + done: + spin_unlock(&dev->slock); + +} + +/* + * IRQ request handler + * + * Runs along with saa7134's IRQ handler, discards anything that isn't + * DMA sound + * + */ + +static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct saa7134_dev *dev = (struct saa7134_dev*) dev_id; + unsigned long report, status; + int loop, handled = 0; + + for (loop = 0; loop < 10; loop++) { + report = saa_readl(SAA7134_IRQ_REPORT); + status = saa_readl(SAA7134_IRQ_STATUS); + + if (report & SAA7134_IRQ_REPORT_DONE_RA3) { + handled = 1; + saa_writel(SAA7134_IRQ_REPORT,report); + saa7134_irq_alsa_done(dev, status); + } else { + goto out; + } + } + + if (loop == 10) { + dprintk("error! looping IRQ!"); + } + +out: + return IRQ_RETVAL(handled); +} + +/* + * ALSA capture trigger + * + * - One of the ALSA capture callbacks. + * + * Called whenever a capture is started or stopped. Must be defined, + * but there's nothing we want to do here + * + */ + +static int snd_card_saa7134_capture_trigger(snd_pcm_substream_t * substream, + int cmd) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_card_saa7134_pcm_t *saapcm = runtime->private_data; + struct saa7134_dev *dev=saapcm->saadev; + int err = 0; + + spin_lock_irq(&dev->slock); + if (cmd == SNDRV_PCM_TRIGGER_START) { + /* start dma */ + saa7134_dma_start(dev); + } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { + /* stop dma */ + saa7134_dma_stop(dev); + } else { + err = -EINVAL; + } + spin_unlock_irq(&dev->slock); + + return err; +} + +/* + * DMA buffer config + * + * Sets the values that will later be used as the size of the buffer, + * size of the fragments, and total number of fragments. + * Must be called during the preparation stage, before memory is + * allocated + * + * - Copied verbatim from saa7134-oss. Can be dropped + * if we just share dsp_buffer_conf from OSS. + */ + +static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks) +{ + if (blksize < 0x100) + blksize = 0x100; + if (blksize > 0x10000) + blksize = 0x10000; + + if (blocks < 2) + blocks = 2; + if ((blksize * blocks) > 1024*1024) + blocks = 1024*1024 / blksize; + + dev->dmasound.blocks = blocks; + dev->dmasound.blksize = blksize; + dev->dmasound.bufsize = blksize * blocks; + + dprintk("buffer config: %d blocks / %d bytes, %d kB total\n", + blocks,blksize,blksize * blocks / 1024); + return 0; +} + +/* + * DMA buffer initialization + * + * Uses V4L functions to initialize the DMA. Shouldn't be necessary in + * ALSA, but I was unable to use ALSA's own DMA, and had to force the + * usage of V4L's + * + * - Copied verbatim from saa7134-oss. Can be dropped + * if we just share dsp_buffer_init from OSS. + */ + +static int dsp_buffer_init(struct saa7134_dev *dev) +{ + int err; + + if (!dev->dmasound.bufsize) + BUG(); + videobuf_dma_init(&dev->dmasound.dma); + err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE, + (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); + if (0 != err) + return err; + return 0; +} + +/* + * ALSA PCM preparation + * + * - One of the ALSA capture callbacks. + * + * Called right after the capture device is opened, this function configures + * the buffer using the previously defined functions, allocates the memory, + * sets up the hardware registers, and then starts the DMA. When this function + * returns, the audio should be flowing. + * + */ + +static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + int err, bswap, sign; + u32 fmt, control; + snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); + struct saa7134_dev *dev; + snd_card_saa7134_pcm_t *saapcm = runtime->private_data; + unsigned int bps; + unsigned long size; + unsigned count; + + size = snd_pcm_lib_buffer_bytes(substream); + count = snd_pcm_lib_period_bytes(substream); + + saapcm->saadev->dmasound.substream = substream; + bps = runtime->rate * runtime->channels; + bps *= snd_pcm_format_width(runtime->format); + bps /= 8; + if (bps <= 0) + return -EINVAL; + saapcm->pcm_bps = bps; + saapcm->pcm_size = snd_pcm_lib_buffer_bytes(substream); + saapcm->pcm_count = snd_pcm_lib_period_bytes(substream); + + + dev=saa7134->saadev; + + dsp_buffer_conf(dev,saapcm->pcm_count,(saapcm->pcm_size/saapcm->pcm_count)); + + err = dsp_buffer_init(dev); + if (0 != err) + goto fail2; + + /* prepare buffer */ + if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma))) + return err; + if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) + goto fail1; + if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt, + dev->dmasound.dma.sglist, + dev->dmasound.dma.sglen, + 0))) + goto fail2; + + + + switch (runtime->format) { + case SNDRV_PCM_FORMAT_U8: + case SNDRV_PCM_FORMAT_S8: + fmt = 0x00; + break; + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + fmt = 0x01; + break; + default: + err = -EINVAL; + return 1; + } + + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + sign = 1; + break; + default: + sign = 0; + break; + } + + switch (runtime->format) { + case SNDRV_PCM_FORMAT_U16_BE: + case SNDRV_PCM_FORMAT_S16_BE: + bswap = 1; break; + default: + bswap = 0; break; + } + + switch (dev->pci->device) { + case PCI_DEVICE_ID_PHILIPS_SAA7134: + if (1 == runtime->channels) + fmt |= (1 << 3); + if (2 == runtime->channels) + fmt |= (3 << 3); + if (sign) + fmt |= 0x04; + + fmt |= (MIXER_ADDR_TVTUNER == dev->dmasound.input) ? 0xc0 : 0x80; + saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff)); + saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8); + saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16); + saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt); + + break; + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + if (1 == runtime->channels) + fmt |= (1 << 4); + if (2 == runtime->channels) + fmt |= (2 << 4); + if (!sign) + fmt |= 0x04; + saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1); + saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24)); + //saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210); + break; + } + + dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", + runtime->format, runtime->channels, fmt, + bswap ? 'b' : '-'); + /* dma: setup channel 6 (= AUDIO) */ + control = SAA7134_RS_CONTROL_BURST_16 | + SAA7134_RS_CONTROL_ME | + (dev->dmasound.pt.dma >> 12); + if (bswap) + control |= SAA7134_RS_CONTROL_BSWAP; + + /* I should be able to use runtime->dma_addr in the control + byte, but it doesn't work. So I allocate the DMA using the + V4L functions, and force ALSA to use that as the DMA area */ + + runtime->dma_area = dev->dmasound.dma.vmalloc; + + saa_writel(SAA7134_RS_BA1(6),0); + saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize); + saa_writel(SAA7134_RS_PITCH(6),0); + saa_writel(SAA7134_RS_CONTROL(6),control); + + dev->dmasound.rate = runtime->rate; + + return 0; + fail2: + saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); + fail1: + videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma); + return err; + + +} + +/* + * ALSA pointer fetching + * + * - One of the ALSA capture callbacks. + * + * Called whenever a period elapses, it must return the current hardware + * position of the buffer. + * Also resets the read counter used to prevent overruns + * + */ + +static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_card_saa7134_pcm_t *saapcm = runtime->private_data; + struct saa7134_dev *dev=saapcm->saadev; + + + + if (dev->dmasound.read_count) { + dev->dmasound.read_count -= snd_pcm_lib_period_bytes(substream); + dev->dmasound.read_offset += snd_pcm_lib_period_bytes(substream); + if (dev->dmasound.read_offset == dev->dmasound.bufsize) + dev->dmasound.read_offset = 0; + } + + return bytes_to_frames(runtime, dev->dmasound.read_offset); +} + +/* + * ALSA hardware capabilities definition + */ + +static snd_pcm_hardware_t snd_card_saa7134_capture = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_U8 | \ + SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_U16_BE, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000, + .rate_min = 32000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (256*1024), + .period_bytes_min = 64, + .period_bytes_max = (256*1024), + .periods_min = 2, + .periods_max = 1024, +}; + +static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime) +{ + snd_card_saa7134_pcm_t *saapcm = runtime->private_data; + + kfree(saapcm); +} + + +/* + * ALSA hardware params + * + * - One of the ALSA capture callbacks. + * + * Called on initialization, right before the PCM preparation + * Usually used in ALSA to allocate the DMA, but since we don't use the + * ALSA DMA it does nothing + * + */ + +static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + + return 0; + + +} + +/* + * ALSA hardware release + * + * - One of the ALSA capture callbacks. + * + * Called after closing the device, but before snd_card_saa7134_capture_close + * Usually used in ALSA to free the DMA, but since we don't use the + * ALSA DMA I'm almost sure this isn't necessary. + * + */ + +static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream) +{ + return 0; +} + +/* + * DMA buffer release + * + * Called after closing the device, during snd_card_saa7134_capture_close + * + */ + +static int dsp_buffer_free(struct saa7134_dev *dev) +{ + if (!dev->dmasound.blksize) + BUG(); + + videobuf_dma_free(&dev->dmasound.dma); + + dev->dmasound.blocks = 0; + dev->dmasound.blksize = 0; + dev->dmasound.bufsize = 0; + + return 0; +} + +/* + * ALSA capture finish + * + * - One of the ALSA capture callbacks. + * + * Called after closing the device. It stops the DMA audio and releases + * the buffers + * + */ + +static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream) +{ + snd_card_saa7134_t *chip = snd_pcm_substream_chip(substream); + struct saa7134_dev *dev = chip->saadev; + + /* unlock buffer */ + saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); + videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma); + + dsp_buffer_free(dev); + return 0; +} + +/* + * ALSA capture start + * + * - One of the ALSA capture callbacks. + * + * Called when opening the device. It creates and populates the PCM + * structure + * + */ + +static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_card_saa7134_pcm_t *saapcm; + snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); + struct saa7134_dev *dev = saa7134->saadev; + int err; + + down(&dev->dmasound.lock); + + dev->dmasound.afmt = SNDRV_PCM_FORMAT_U8; + dev->dmasound.channels = 2; + dev->dmasound.read_count = 0; + dev->dmasound.read_offset = 0; + + up(&dev->dmasound.lock); + + saapcm = kzalloc(sizeof(*saapcm), GFP_KERNEL); + if (saapcm == NULL) + return -ENOMEM; + saapcm->saadev=saa7134->saadev; + + spin_lock_init(&saapcm->lock); + + saapcm->substream = substream; + runtime->private_data = saapcm; + runtime->private_free = snd_card_saa7134_runtime_free; + runtime->hw = snd_card_saa7134_capture; + + if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + return err; + + return 0; +} + +/* + * ALSA capture callbacks definition + */ + +static snd_pcm_ops_t snd_card_saa7134_capture_ops = { + .open = snd_card_saa7134_capture_open, + .close = snd_card_saa7134_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_card_saa7134_hw_params, + .hw_free = snd_card_saa7134_hw_free, + .prepare = snd_card_saa7134_capture_prepare, + .trigger = snd_card_saa7134_capture_trigger, + .pointer = snd_card_saa7134_capture_pointer, +}; + +/* + * ALSA PCM setup + * + * Called when initializing the board. Sets up the name and hooks up + * the callbacks + * + */ + +static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device) +{ + snd_pcm_t *pcm; + int err; + + if ((err = snd_pcm_new(saa7134->card, "SAA7134 PCM", device, 0, 1, &pcm)) < 0) + return err; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_saa7134_capture_ops); + pcm->private_data = saa7134; + pcm->info_flags = 0; + strcpy(pcm->name, "SAA7134 PCM"); + return 0; +} + +#define SAA713x_VOLUME(xname, xindex, addr) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .info = snd_saa7134_volume_info, \ + .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \ + .private_value = addr } + +static int snd_saa7134_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 20; + return 0; +} + +static int snd_saa7134_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); + int addr = kcontrol->private_value; + + ucontrol->value.integer.value[0] = chip->mixer_volume[addr][0]; + ucontrol->value.integer.value[1] = chip->mixer_volume[addr][1]; + return 0; +} + +static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change, addr = kcontrol->private_value; + int left, right; + + left = ucontrol->value.integer.value[0]; + if (left < 0) + left = 0; + if (left > 20) + left = 20; + right = ucontrol->value.integer.value[1]; + if (right < 0) + right = 0; + if (right > 20) + right = 20; + spin_lock_irqsave(&chip->mixer_lock, flags); + change = chip->mixer_volume[addr][0] != left || + chip->mixer_volume[addr][1] != right; + chip->mixer_volume[addr][0] = left; + chip->mixer_volume[addr][1] = right; + spin_unlock_irqrestore(&chip->mixer_lock, flags); + return change; +} + +#define SAA713x_CAPSRC(xname, xindex, addr) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .info = snd_saa7134_capsrc_info, \ + .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \ + .private_value = addr } + +static int snd_saa7134_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int addr = kcontrol->private_value; + + spin_lock_irqsave(&chip->mixer_lock, flags); + ucontrol->value.integer.value[0] = chip->capture_source[addr][0]; + ucontrol->value.integer.value[1] = chip->capture_source[addr][1]; + spin_unlock_irqrestore(&chip->mixer_lock, flags); + return 0; +} + +static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change, addr = kcontrol->private_value; + int left, right; + u32 anabar, xbarin; + int analog_io, rate; + struct saa7134_dev *dev; + + dev = chip->saadev; + + left = ucontrol->value.integer.value[0] & 1; + right = ucontrol->value.integer.value[1] & 1; + spin_lock_irqsave(&chip->mixer_lock, flags); + + change = chip->capture_source[addr][0] != left || + chip->capture_source[addr][1] != right; + chip->capture_source[addr][0] = left; + chip->capture_source[addr][1] = right; + dev->dmasound.input=addr; + spin_unlock_irqrestore(&chip->mixer_lock, flags); + + + if (change) { + switch (dev->pci->device) { + + case PCI_DEVICE_ID_PHILIPS_SAA7134: + switch (addr) { + case MIXER_ADDR_TVTUNER: + saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0); + saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00); + break; + case MIXER_ADDR_LINE1: + case MIXER_ADDR_LINE2: + analog_io = (MIXER_ADDR_LINE1 == addr) ? 0x00 : 0x08; + rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03; + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io); + saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80); + saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate); + break; + } + + break; + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + xbarin = 0x03; // adc + anabar = 0; + switch (addr) { + case MIXER_ADDR_TVTUNER: + xbarin = 0; // Demodulator + anabar = 2; // DACs + break; + case MIXER_ADDR_LINE1: + anabar = 0; // aux1, aux1 + break; + case MIXER_ADDR_LINE2: + anabar = 9; // aux2, aux2 + break; + } + + /* output xbar always main channel */ + saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10); + + if (left || right) { // We've got data, turn the input on + saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, xbarin); + saa_writel(SAA7133_ANALOG_IO_SELECT, anabar); + } else { + saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, 0); + saa_writel(SAA7133_ANALOG_IO_SELECT, 0); + } + break; + } + } + + return change; +} + +static snd_kcontrol_new_t snd_saa7134_controls[] = { +SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER), +SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER), +SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1), +SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1), +SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2), +SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2), +}; + +/* + * ALSA mixer setup + * + * Called when initializing the board. Sets up the name and hooks up + * the callbacks + * + */ + +static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip) +{ + snd_card_t *card = chip->card; + unsigned int idx; + int err; + + snd_assert(chip != NULL, return -EINVAL); + strcpy(card->mixername, "SAA7134 Mixer"); + + for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_controls); idx++) { + if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_saa7134_controls[idx], chip))) < 0) + return err; + } + return 0; +} + +static int snd_saa7134_free(snd_card_saa7134_t *chip) +{ + return 0; +} + +static int snd_saa7134_dev_free(snd_device_t *device) +{ + snd_card_saa7134_t *chip = device->device_data; + return snd_saa7134_free(chip); +} + +/* + * ALSA initialization + * + * Called by saa7134-core, it creates the basic structures and registers + * the ALSA devices + * + */ + +int alsa_card_saa7134_create (struct saa7134_dev *saadev) +{ + static int dev; + + snd_card_t *card; + snd_card_saa7134_t *chip; + int err; + static snd_device_ops_t ops = { + .dev_free = snd_saa7134_dev_free, + }; + + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) + return -ENODEV; + + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + + if (card == NULL) + return -ENOMEM; + + strcpy(card->driver, "SAA7134"); + + /* Card "creation" */ + + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + return -ENOMEM; + } + + spin_lock_init(&chip->lock); + spin_lock_init(&chip->mixer_lock); + + chip->saadev = saadev; + + chip->card = card; + + chip->pci = saadev->pci; + chip->irq = saadev->pci->irq; + chip->iobase = pci_resource_start(saadev->pci, 0); + + err = request_irq(saadev->pci->irq, saa7134_alsa_irq, + SA_SHIRQ | SA_INTERRUPT, saadev->name, saadev); + + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n", + saadev->name, saadev->pci->irq); + goto __nodev; + } + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + goto __nodev; + } + + if ((err = snd_card_saa7134_new_mixer(chip)) < 0) + goto __nodev; + + if ((err = snd_card_saa7134_pcm(chip, 0)) < 0) + goto __nodev; + + snd_card_set_dev(card, &chip->pci->dev); + + /* End of "creation" */ + + strcpy(card->shortname, "SAA7134"); + sprintf(card->longname, "%s at 0x%lx irq %d", + chip->saadev->name, chip->iobase, chip->irq); + + if ((err = snd_card_register(card)) == 0) { + snd_saa7134_cards[dev] = card; + return 0; + } + +__nodev: + snd_card_free(card); + kfree(chip); + return err; +} + +/* + * Module initializer + * + * Loops through present saa7134 cards, and assigns an ALSA device + * to each one + * + */ + +static int saa7134_alsa_init(void) +{ + struct saa7134_dev *saadev = NULL; + struct list_head *list; + + printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); + + list_for_each(list,&saa7134_devlist) { + saadev = list_entry(list, struct saa7134_dev, devlist); + alsa_card_saa7134_create(saadev); + } + + if (saadev == NULL) + printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n"); + + return 0; + +} + +/* + * Module destructor + */ + +void saa7134_alsa_exit(void) +{ + int idx; + + for (idx = 0; idx < SNDRV_CARDS; idx++) { + snd_card_free(snd_saa7134_cards[idx]); + } + + printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n"); + + return; +} + +module_init(saa7134_alsa_init); +module_exit(saa7134_alsa_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ricardo Cerqueira"); diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index acc7a4335e23..663d03e5bc67 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -191,10 +191,14 @@ struct saa7134_board saa7134_boards[] = { .amux = TV, .tv = 1, },{ - .name = name_comp1, + .name = name_comp1, /* Composite signal on S-Video input */ .vmux = 0, .amux = LINE2, },{ + .name = name_comp2, /* Composite input */ + .vmux = 3, + .amux = LINE2, + },{ .name = name_svideo, .vmux = 8, .amux = LINE2, @@ -2109,8 +2113,423 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x01, }, }, -}; + [SAA7134_BOARD_BEHOLD_409FM] = { + /* <http://tuner.beholder.ru>, Sergey <skiv@orel.ru> */ + .name = "Beholder BeholdTV 409 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_GOTVIEW_7135] = { + /* Mike Baikov <mike@baikov.com> */ + /* Andrey Cvetcov <ays14@yandex.ru> */ + .name = "GoTView 7135 PCI", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x00200003, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x00200003, + },{ + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .gpio = 0x00200003, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x00200003, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x00200003, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x00200003, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x00200003, + }, + }, + [SAA7134_BOARD_PHILIPS_EUROPA] = { + .name = "Philips EUROPA V3 reference design", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TD1316, + .radio_type = UNSET, + .tuner_addr = 0x61, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, + [SAA7134_BOARD_VIDEOMATE_DVBT_300] = { + .name = "Compro Videomate DVB-T300", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TD1316, + .radio_type = UNSET, + .tuner_addr = 0x61, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, + [SAA7134_BOARD_VIDEOMATE_DVBT_200] = { + .name = "Compro Videomate DVB-T200", + .tuner_type = TUNER_ABSENT, + .audio_clock = 0x00187de7, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_RTD_VFG7350] = { + .name = "RTD Embedded Technologies VFG7350", + .audio_clock = 0x00200000, + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = "Composite 0", + .vmux = 0, + .amux = LINE1, + },{ + .name = "Composite 1", + .vmux = 1, + .amux = LINE2, + },{ + .name = "Composite 2", + .vmux = 2, + .amux = LINE1, + },{ + .name = "Composite 3", + .vmux = 3, + .amux = LINE2, + },{ + .name = "S-Video 0", + .vmux = 8, + .amux = LINE1, + },{ + .name = "S-Video 1", + .vmux = 9, + .amux = LINE2, + }}, + .mpeg = SAA7134_MPEG_EMPRESS, + .video_out = CCIR656, + .vid_port_opts = ( SET_T_CODE_POLARITY_NON_INVERTED | + SET_CLOCK_NOT_DELAYED | + SET_CLOCK_INVERTED | + SET_VSYNC_OFF ), + }, + [SAA7134_BOARD_RTD_VFG7330] = { + .name = "RTD Embedded Technologies VFG7330", + .audio_clock = 0x00200000, + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = "Composite 0", + .vmux = 0, + .amux = LINE1, + },{ + .name = "Composite 1", + .vmux = 1, + .amux = LINE2, + },{ + .name = "Composite 2", + .vmux = 2, + .amux = LINE1, + },{ + .name = "Composite 3", + .vmux = 3, + .amux = LINE2, + },{ + .name = "S-Video 0", + .vmux = 8, + .amux = LINE1, + },{ + .name = "S-Video 1", + .vmux = 9, + .amux = LINE2, + }}, + }, + [SAA7134_BOARD_FLYTVPLATINUM_MINI2] = { + .name = "LifeView FlyTV Platinum Mini2", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, /* Composite signal on S-Video input */ + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, /* Composite input */ + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, + [SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180] = { + /* Michael Krufky <mkrufky@m1k.net> + * Uses Alps Electric TDHU2, containing NXT2004 ATSC Decoder + * AFAIK, there is no analog demod, thus, + * no support for analog television. + */ + .name = "AVerMedia AVerTVHD MCE A180", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_comp1, + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, + [SAA7134_BOARD_MONSTERTV_MOBILE] = { + .name = "SKNet MonsterTV Mobile", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 6, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_PINNACLE_PCTV_110i] = { + .name = "Pinnacle PCTV 110i (saa7133)", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x080200000, + .inputs = {{ + .name = name_tv, + .vmux = 4, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + }, + }, + [SAA7134_BOARD_ASUSTeK_P7131_DUAL] = { + .name = "ASUSTeK P7131 Dual", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 1 << 21, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0200000, + }, + }, + [SAA7134_BOARD_SEDNA_PC_TV_CARDBUS] = { + /* Paul Tom Zalac <pzalac@gmail.com> */ + /* Pavel Mihaylov <bin@bash.info> */ + .name = "Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)", + /* Sedna/MuchTV (OEM) Cardbus TV Tuner */ + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0xe880c0, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 6, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV] = { + /* "Cyril Lacoux (Yack)" <clacoux@ifeelgood.org> */ + .name = "ASUS Digimatrix TV", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .tda9887_conf = TDA9887_PRESENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_PHILIPS_TIGER] = { + .name = "Philips Tiger reference design", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, +}; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -2145,19 +2564,19 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153B, + .subvendor = 0x153b, .subdevice = 0x1142, .driver_data = SAA7134_BOARD_CINERGY400, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153B, + .subvendor = 0x153b, .subdevice = 0x1143, .driver_data = SAA7134_BOARD_CINERGY600, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153B, + .subvendor = 0x153b, .subdevice = 0x1158, .driver_data = SAA7134_BOARD_CINERGY600_MK3, },{ @@ -2193,6 +2612,18 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x14c0, + .subdevice = 0x1212, /* minipci, LR1212 */ + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI2, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x4e42, + .subdevice = 0x0212, /* OEM minipci, LR212 */ + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5168, /* Animation Technologies (LifeView) */ .subdevice = 0x0214, /* Standard PCI, LR214WF */ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, @@ -2369,7 +2800,7 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x153B, + .subvendor = 0x153b, .subdevice = 0x1152, .driver_data = SAA7134_BOARD_CINERGY200, },{ @@ -2434,13 +2865,18 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1421, .subdevice = 0x0350, /* PCI version */ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1421, .subdevice = 0x0370, /* cardbus version */ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1421, + .subdevice = 0x1370, /* cardbus version */ + .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, },{ /* Typhoon DVB-T Duo Digital/Analog Cardbus */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -2459,9 +2895,81 @@ struct pci_device_id saa7134_pci_tbl[] = { .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x1043, .subdevice = 0x0210, /* mini pci PAL/SECAM version */ - .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX, + .driver_data = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV, },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0000, /* It shouldn't break anything, since subdevice id seems unique */ + .subdevice = 0x4091, + .driver_data = SAA7134_BOARD_BEHOLD_409FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5456, /* GoTView */ + .subdevice = 0x7135, + .driver_data = SAA7134_BOARD_GOTVIEW_7135, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = PCI_VENDOR_ID_PHILIPS, + .subdevice = 0x2004, + .driver_data = SAA7134_BOARD_PHILIPS_EUROPA, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x185b, + .subdevice = 0xc900, + .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_300, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x185b, + .subdevice = 0xc901, + .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_200, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1435, + .subdevice = 0x7350, + .driver_data = SAA7134_BOARD_RTD_VFG7350, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1435, + .subdevice = 0x7330, + .driver_data = SAA7134_BOARD_RTD_VFG7330, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, + .subdevice = 0x1044, + .driver_data = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1131, + .subdevice = 0x4ee9, + .driver_data = SAA7134_BOARD_MONSTERTV_MOBILE, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x11bd, + .subdevice = 0x002e, + .driver_data = SAA7134_BOARD_PINNACLE_PCTV_110i, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1043, + .subdevice = 0x4862, + .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = PCI_VENDOR_ID_PHILIPS, + .subdevice = 0x2018, + .driver_data = SAA7134_BOARD_PHILIPS_TIGER, + },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -2530,9 +3038,10 @@ int saa7134_board_init1(struct saa7134_dev *dev) switch (dev->board) { case SAA7134_BOARD_FLYVIDEO2000: case SAA7134_BOARD_FLYVIDEO3000: - dev->has_remote = 1; + dev->has_remote = SAA7134_REMOTE_GPIO; board_flyvideo(dev); break; + case SAA7134_BOARD_FLYTVPLATINUM_MINI2: case SAA7134_BOARD_FLYTVPLATINUM_FM: case SAA7134_BOARD_CINERGY400: case SAA7134_BOARD_CINERGY600: @@ -2550,10 +3059,16 @@ int saa7134_board_init1(struct saa7134_dev *dev) /* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */ case SAA7134_BOARD_VIDEOMATE_TV_PVR: case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: + case SAA7134_BOARD_VIDEOMATE_DVBT_300: + case SAA7134_BOARD_VIDEOMATE_DVBT_200: case SAA7134_BOARD_MANLI_MTV001: case SAA7134_BOARD_MANLI_MTV002: + case SAA7134_BOARD_BEHOLD_409FM: case SAA7134_BOARD_AVACSSMARTTV: - dev->has_remote = 1; + case SAA7134_BOARD_GOTVIEW_7135: + case SAA7134_BOARD_KWORLD_TERMINATOR: + case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: + dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_MD5044: printk("%s: seems there are two different versions of the MD5044\n" @@ -2565,11 +3080,14 @@ int saa7134_board_init1(struct saa7134_dev *dev) /* power-up tuner chip */ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000); - msleep(1); + case SAA7134_BOARD_MONSTERTV_MOBILE: + /* power-up tuner chip */ + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000004); break; case SAA7134_BOARD_FLYDVBTDUO: case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS: - /* turn the fan on Hac: static for the time being */ + /* turn the fan on */ saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06); break; @@ -2579,6 +3097,22 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff); msleep(1); break; + case SAA7134_BOARD_RTD_VFG7350: + + /* + * Make sure Production Test Register at offset 0x1D1 is cleared + * to take chip out of test mode. Clearing bit 4 (TST_EN_AOUT) + * prevents pin 105 from remaining low; keeping pin 105 low + * continually resets the SAA6752 chip. + */ + + saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00); + break; + /* i2c remotes */ + case SAA7134_BOARD_PINNACLE_PCTV_110i: + case SAA7134_BOARD_UPMOST_PURPLE_TV: + dev->has_remote = SAA7134_REMOTE_I2C; + break; } return 0; } @@ -2613,7 +3147,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup); } break; -case SAA7134_BOARD_MD7134: + case SAA7134_BOARD_MD7134: { struct tuner_setup tun_setup; u8 subaddr; @@ -2680,6 +3214,33 @@ case SAA7134_BOARD_MD7134: saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); } break; + case SAA7134_BOARD_PHILIPS_EUROPA: + case SAA7134_BOARD_VIDEOMATE_DVBT_300: + /* The Philips EUROPA based hybrid boards have the tuner connected through + * the channel decoder. We have to make it transparent to find it + */ + { + struct tuner_setup tun_setup; + u8 data[] = { 0x07, 0x02}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + i2c_transfer(&dev->i2c_adap, &msg, 1); + + tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + + saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); + } + break; + case SAA7134_BOARD_PHILIPS_TIGER: + case SAA7134_BOARD_ASUSTeK_P7131_DUAL: + /* this is a hybrid board, initialize to analog mode */ + { + u8 data[] = { 0x3c, 0x33, 0x68}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + i2c_transfer(&dev->i2c_adap, &msg, 1); + } + break; } return 0; } diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index e5e36f3c6250..19b88744fb31 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -57,6 +57,10 @@ static unsigned int oss = 0; module_param(oss, int, 0444); MODULE_PARM_DESC(oss,"register oss devices (default: no)"); +static unsigned int alsa = 0; +module_param(alsa, int, 0444); +MODULE_PARM_DESC(alsa,"register alsa devices (default: no)"); + static unsigned int latency = UNSET; module_param(latency, int, 0444); MODULE_PARM_DESC(latency,"pci latency timer"); @@ -190,6 +194,7 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) static int need_empress; static int need_dvb; +static int need_alsa; static int pending_call(struct notifier_block *self, unsigned long state, void *module) @@ -197,10 +202,12 @@ static int pending_call(struct notifier_block *self, unsigned long state, if (module != THIS_MODULE || state != MODULE_STATE_LIVE) return NOTIFY_DONE; - if (need_empress) - request_module("saa7134-empress"); - if (need_dvb) - request_module("saa7134-dvb"); + if (need_empress) + request_module("saa7134-empress"); + if (need_dvb) + request_module("saa7134-dvb"); + if (need_alsa) + request_module("saa7134-alsa"); return NOTIFY_DONE; } @@ -275,8 +282,8 @@ unsigned long saa7134_buffer_base(struct saa7134_buf *buf) int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt) { - __le32 *cpu; - dma_addr_t dma_addr; + __le32 *cpu; + dma_addr_t dma_addr; cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr); if (NULL == cpu) @@ -436,7 +443,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) ctrl |= SAA7134_MAIN_CTRL_TE0; irq |= SAA7134_IRQ1_INTE_RA0_1 | SAA7134_IRQ1_INTE_RA0_0; - cap = dev->video_q.curr->vb.field; + cap = dev->video_q.curr->vb.field; } /* video capture -- dma 1+2 (planar modes) */ @@ -465,7 +472,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) } /* audio capture -- dma 3 */ - if (dev->oss.dma_running) { + if (dev->dmasound.dma_running) { ctrl |= SAA7134_MAIN_CTRL_TE6; irq |= SAA7134_IRQ1_INTE_RA3_1 | SAA7134_IRQ1_INTE_RA3_0; @@ -570,6 +577,17 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) dev->name); goto out; } + + /* If alsa support is active and we get a sound report, exit + and let the saa7134-alsa module deal with it */ + + if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && alsa) { + if (irq_debug > 1) + printk(KERN_DEBUG "%s/irq: ignoring interrupt for ALSA\n", + dev->name); + goto out; + } + handled = 1; saa_writel(SAA7134_IRQ_REPORT,report); if (irq_debug) @@ -591,13 +609,17 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) card_has_mpeg(dev)) saa7134_irq_ts_done(dev,status); - if ((report & SAA7134_IRQ_REPORT_DONE_RA3)) - saa7134_irq_oss_done(dev,status); + if ((report & SAA7134_IRQ_REPORT_DONE_RA3)) { + if (oss) { + saa7134_irq_oss_done(dev,status); + } + } if ((report & (SAA7134_IRQ_REPORT_GPIO16 | SAA7134_IRQ_REPORT_GPIO18)) && dev->remote) saa7134_input_irq(dev); + } if (10 == loop) { @@ -636,7 +658,7 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) saa_writel(SAA7134_IRQ1, 0); saa_writel(SAA7134_IRQ2, 0); - init_MUTEX(&dev->lock); + init_MUTEX(&dev->lock); spin_lock_init(&dev->slock); saa7134_track_gpio(dev,"pre-init"); @@ -646,14 +668,6 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) saa7134_ts_init1(dev); saa7134_input_init1(dev); - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - saa7134_oss_init1(dev); - break; - } - /* RAM FIFO config */ saa_writel(SAA7134_FIFO_SIZE, 0x08070503); saa_writel(SAA7134_THRESHOULD,0x02020202); @@ -668,6 +682,21 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) SAA7134_MAIN_CTRL_ESFE | SAA7134_MAIN_CTRL_EBDAC); + /* + * Initialize OSS _after_ enabling audio clock PLL and audio processing. + * OSS initialization writes to registers via the audio DSP; these + * writes will fail unless the audio clock has been started. At worst, + * audio will not work. + */ + + switch (dev->pci->device) { + case PCI_DEVICE_ID_PHILIPS_SAA7134: + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + saa7134_oss_init1(dev); + break; + } + /* enable peripheral devices */ saa_writeb(SAA7134_SPECIAL_MODE, 0x01); @@ -687,7 +716,7 @@ static int saa7134_hwinit2(struct saa7134_dev *dev) saa7134_tvaudio_init2(dev); /* enable IRQ's */ - irq2_mask = + irq2_mask = SAA7134_IRQ2_INTE_DEC3 | SAA7134_IRQ2_INTE_DEC2 | SAA7134_IRQ2_INTE_DEC1 | @@ -695,10 +724,12 @@ static int saa7134_hwinit2(struct saa7134_dev *dev) SAA7134_IRQ2_INTE_PE | SAA7134_IRQ2_INTE_AR; - if (dev->has_remote) + if (dev->has_remote == SAA7134_REMOTE_GPIO) irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 | SAA7134_IRQ2_INTE_GPIO18A | SAA7134_IRQ2_INTE_GPIO16 ); + else if (dev->has_remote == SAA7134_REMOTE_I2C) + request_module("ir-kbd-i2c"); saa_writel(SAA7134_IRQ1, 0); saa_writel(SAA7134_IRQ2, irq2_mask); @@ -872,8 +903,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, /* print pci info */ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); + printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " "latency: %d, mmio: 0x%lx\n", dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat,pci_resource_start(pci_dev,0)); @@ -897,7 +928,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; if (UNSET != tuner[dev->nr]) dev->tuner_type = tuner[dev->nr]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", dev->name,pci_dev->subsystem_vendor, pci_dev->subsystem_device,saa7134_boards[dev->board].name, dev->board, card[dev->nr] == dev->board ? @@ -947,14 +978,20 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, request_module("tuner"); if (dev->tda9887_conf) request_module("tda9887"); - if (card_is_empress(dev)) { + if (card_is_empress(dev)) { request_module("saa6752hs"); request_module_depend("saa7134-empress",&need_empress); } - if (card_is_dvb(dev)) + if (card_is_dvb(dev)) request_module_depend("saa7134-dvb",&need_dvb); + if (!oss && alsa) { + dprintk("Requesting ALSA module\n"); + request_module_depend("saa7134-alsa",&need_alsa); + } + + v4l2_prio_init(&dev->prio); /* register v4l devices */ @@ -993,22 +1030,22 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, case PCI_DEVICE_ID_PHILIPS_SAA7133: case PCI_DEVICE_ID_PHILIPS_SAA7135: if (oss) { - err = dev->oss.minor_dsp = + err = dev->dmasound.minor_dsp = register_sound_dsp(&saa7134_dsp_fops, dsp_nr[dev->nr]); if (err < 0) { goto fail4; } printk(KERN_INFO "%s: registered device dsp%d\n", - dev->name,dev->oss.minor_dsp >> 4); + dev->name,dev->dmasound.minor_dsp >> 4); - err = dev->oss.minor_mixer = + err = dev->dmasound.minor_mixer = register_sound_mixer(&saa7134_mixer_fops, mixer_nr[dev->nr]); if (err < 0) goto fail5; printk(KERN_INFO "%s: registered device mixer%d\n", - dev->name,dev->oss.minor_mixer >> 4); + dev->name,dev->dmasound.minor_mixer >> 4); } break; } @@ -1035,7 +1072,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, case PCI_DEVICE_ID_PHILIPS_SAA7133: case PCI_DEVICE_ID_PHILIPS_SAA7135: if (oss) - unregister_sound_dsp(dev->oss.minor_dsp); + unregister_sound_dsp(dev->dmasound.minor_dsp); break; } fail4: @@ -1055,7 +1092,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, static void __devexit saa7134_finidev(struct pci_dev *pci_dev) { - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + struct saa7134_dev *dev = pci_get_drvdata(pci_dev); struct list_head *item; struct saa7134_mpeg_ops *mops; @@ -1093,8 +1130,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) case PCI_DEVICE_ID_PHILIPS_SAA7133: case PCI_DEVICE_ID_PHILIPS_SAA7135: if (oss) { - unregister_sound_mixer(dev->oss.minor_mixer); - unregister_sound_dsp(dev->oss.minor_dsp); + unregister_sound_mixer(dev->dmasound.minor_mixer); + unregister_sound_dsp(dev->dmasound.minor_dsp); } break; } @@ -1149,10 +1186,10 @@ EXPORT_SYMBOL(saa7134_ts_unregister); /* ----------------------------------------------------------- */ static struct pci_driver saa7134_pci_driver = { - .name = "saa7134", - .id_table = saa7134_pci_tbl, - .probe = saa7134_initdev, - .remove = __devexit_p(saa7134_finidev), + .name = "saa7134", + .id_table = saa7134_pci_tbl, + .probe = saa7134_initdev, + .remove = __devexit_p(saa7134_finidev), }; static int saa7134_init(void) @@ -1188,6 +1225,13 @@ EXPORT_SYMBOL(saa7134_i2c_call_clients); EXPORT_SYMBOL(saa7134_devlist); EXPORT_SYMBOL(saa7134_boards); +/* ----------------- For ALSA -------------------------------- */ + +EXPORT_SYMBOL(saa7134_pgtable_free); +EXPORT_SYMBOL(saa7134_pgtable_build); +EXPORT_SYMBOL(saa7134_pgtable_alloc); +EXPORT_SYMBOL(saa7134_set_dmabits); + /* ----------------------------------------------------------- */ /* * Local variables: diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 639ae51a052d..e016480c3468 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -29,7 +29,6 @@ #include <linux/kthread.h> #include <linux/suspend.h> - #include "saa7134-reg.h" #include "saa7134.h" @@ -40,6 +39,10 @@ #ifdef HAVE_TDA1004X # include "tda1004x.h" #endif +#ifdef HAVE_NXT200X +# include "nxt200x.h" +# include "dvb-pll.h" +#endif MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); @@ -151,25 +154,12 @@ static struct mt352_config pinnacle_300i = { /* ------------------------------------------------------------------ */ #ifdef HAVE_TDA1004X -static int philips_tu1216_pll_init(struct dvb_frontend *fe) -{ - struct saa7134_dev *dev = fe->dvb->priv; - static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; - - /* setup PLL configuration */ - if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - msleep(1); - return 0; -} - -static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct saa7134_dev *dev = fe->dvb->priv; u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = + struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; int tuner_frequency = 0; u8 band, cp, filter; @@ -242,11 +232,36 @@ static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) return -EIO; + msleep(1); + return 0; +} +static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; + + /* setup PLL configuration */ + if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; msleep(1); + return 0; } +/* ------------------------------------------------------------------ */ + +static int philips_tu1216_pll_60_init(struct dvb_frontend *fe) +{ + return philips_tda6651_pll_init(0x60, fe); +} + +static int philips_tu1216_pll_60_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + return philips_tda6651_pll_set(0x60, fe, params); +} + static int philips_tu1216_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) { @@ -254,22 +269,108 @@ static int philips_tu1216_request_firmware(struct dvb_frontend *fe, return request_firmware(fw, name, &dev->pci->dev); } -static struct tda1004x_config philips_tu1216_config = { +static struct tda1004x_config philips_tu1216_60_config = { + + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .pll_init = philips_tu1216_pll_60_init, + .pll_set = philips_tu1216_pll_60_set, + .pll_sleep = NULL, + .request_firmware = philips_tu1216_request_firmware, +}; + +/* ------------------------------------------------------------------ */ + +static int philips_tu1216_pll_61_init(struct dvb_frontend *fe) +{ + return philips_tda6651_pll_init(0x61, fe); +} + +static int philips_tu1216_pll_61_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + return philips_tda6651_pll_set(0x61, fe, params); +} + +static struct tda1004x_config philips_tu1216_61_config = { .demod_address = 0x8, .invert = 1, - .invert_oclk = 1, + .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_4M, .agc_config = TDA10046_AGC_DEFAULT, .if_freq = TDA10046_FREQ_3617, - .pll_init = philips_tu1216_pll_init, - .pll_set = philips_tu1216_pll_set, + .pll_init = philips_tu1216_pll_61_init, + .pll_set = philips_tu1216_pll_61_set, .pll_sleep = NULL, .request_firmware = philips_tu1216_request_firmware, }; /* ------------------------------------------------------------------ */ +static int philips_europa_pll_init(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab }; + struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) }; + + /* setup PLL configuration */ + if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) + return -EIO; + msleep(1); + + /* switch the board to dvb mode */ + init_msg.addr = 0x43; + init_msg.len = 0x02; + msg[0] = 0x00; + msg[1] = 0x40; + if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) + return -EIO; + + return 0; +} + +static int philips_td1316_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + return philips_tda6651_pll_set(0x61, fe, params); +} + +static void philips_europa_analog(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + /* this message actually turns the tuner back to analog mode */ + static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 }; + struct i2c_msg analog_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) }; + + i2c_transfer(&dev->i2c_adap, &analog_msg, 1); + msleep(1); + + /* switch the board to analog mode */ + analog_msg.addr = 0x43; + analog_msg.len = 0x02; + msg[0] = 0x00; + msg[1] = 0x14; + i2c_transfer(&dev->i2c_adap, &analog_msg, 1); +} + +static struct tda1004x_config philips_europa_config = { + + .demod_address = 0x8, + .invert = 0, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_IFO_AUTO_POS, + .if_freq = TDA10046_FREQ_052, + .pll_init = philips_europa_pll_init, + .pll_set = philips_td1316_pll_set, + .pll_sleep = philips_europa_analog, + .request_firmware = NULL, +}; + +/* ------------------------------------------------------------------ */ static int philips_fmd1216_pll_init(struct dvb_frontend *fe) { @@ -382,7 +483,6 @@ static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ return 0; } -#ifdef HAVE_TDA1004X static struct tda1004x_config medion_cardbus = { .demod_address = 0x08, .invert = 1, @@ -395,7 +495,6 @@ static struct tda1004x_config medion_cardbus = { .pll_sleep = philips_fmd1216_analog, .request_firmware = NULL, }; -#endif /* ------------------------------------------------------------------ */ @@ -452,7 +551,7 @@ static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ u8 tuner_buf[14]; struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf, - .len = sizeof(tuner_buf) }; + .len = sizeof(tuner_buf) }; int i, tuner_freq, if_freq; u32 N; switch (params->u.ofdm.bandwidth) { @@ -511,7 +610,7 @@ static void philips_tda827x_pll_sleep(struct dvb_frontend *fe) struct saa7134_dev *dev = fe->dvb->priv; static u8 tda827x_sleep[] = { 0x30, 0xd0}; struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep, - .len = sizeof(tda827x_sleep) }; + .len = sizeof(tda827x_sleep) }; i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); } @@ -527,6 +626,202 @@ static struct tda1004x_config tda827x_lifeview_config = { .pll_sleep = philips_tda827x_pll_sleep, .request_firmware = NULL, }; + +/* ------------------------------------------------------------------ */ + +struct tda827xa_data { + u32 lomax; + u8 svco; + u8 spd; + u8 scr; + u8 sbs; + u8 gc3; +}; + +static struct tda827xa_data tda827xa_dvbt[] = { + { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, + { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}}; + + +static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct saa7134_dev *dev = fe->dvb->priv; + u8 tuner_buf[14]; + unsigned char reg2[2]; + + struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf}; + int i, tuner_freq, if_freq; + u32 N; + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + if_freq = 4000000; + break; + case BANDWIDTH_7_MHZ: + if_freq = 4500000; + break; + default: /* 8 MHz or Auto */ + if_freq = 5000000; + break; + } + tuner_freq = params->frequency + if_freq; + + i = 0; + while (tda827xa_dvbt[i].lomax < tuner_freq) { + if(tda827xa_dvbt[i + 1].lomax == 0) + break; + i++; + } + + N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd; + tuner_buf[0] = 0; // subaddress + tuner_buf[1] = N >> 8; + tuner_buf[2] = N & 0xff; + tuner_buf[3] = 0; + tuner_buf[4] = 0x16; + tuner_buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) + + tda827xa_dvbt[i].sbs; + tuner_buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4); + tuner_buf[7] = 0x0c; + tuner_buf[8] = 0x06; + tuner_buf[9] = 0x24; + tuner_buf[10] = 0xff; + tuner_buf[11] = 0x60; + tuner_buf[12] = 0x00; + tuner_buf[13] = 0x39; // lpsel + msg.len = 14; + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) + return -EIO; + + msg.buf= reg2; + msg.len = 2; + reg2[0] = 0x60; + reg2[1] = 0x3c; + i2c_transfer(&dev->i2c_adap, &msg, 1); + + reg2[0] = 0xa0; + reg2[1] = 0x40; + i2c_transfer(&dev->i2c_adap, &msg, 1); + + msleep(2); + /* correct CP value */ + reg2[0] = 0x30; + reg2[1] = 0x10 + tda827xa_dvbt[i].scr; + msg.len = 2; + i2c_transfer(&dev->i2c_adap, &msg, 1); + + msleep(550); + reg2[0] = 0x50; + reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4); + i2c_transfer(&dev->i2c_adap, &msg, 1); + + return 0; + +} + +static void philips_tda827xa_pll_sleep(u8 addr, struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 tda827xa_sleep[] = { 0x30, 0x90}; + struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep, + .len = sizeof(tda827xa_sleep) }; + i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + +} + +/* ------------------------------------------------------------------ */ + +static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + int ret; + struct saa7134_dev *dev = fe->dvb->priv; + static u8 tda8290_close[] = { 0x21, 0xc0}; + static u8 tda8290_open[] = { 0x21, 0x80}; + struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2}; + /* close tda8290 i2c bridge */ + tda8290_msg.buf = tda8290_close; + ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); + if (ret != 1) + return -EIO; + msleep(20); + ret = philips_tda827xa_pll_set(0x61, fe, params); + if (ret != 0) + return ret; + /* open tda8290 i2c bridge */ + tda8290_msg.buf = tda8290_open; + i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); + return ret; +}; + +static int philips_tiger_dvb_mode(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x6a}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static void philips_tiger_analog_mode(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x68}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + + i2c_transfer(&dev->i2c_adap, &msg, 1); + philips_tda827xa_pll_sleep( 0x61, fe); +} + +static struct tda1004x_config philips_tiger_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .if_freq = TDA10046_FREQ_045, + .pll_init = philips_tiger_dvb_mode, + .pll_set = philips_tiger_pll_set, + .pll_sleep = philips_tiger_analog_mode, + .request_firmware = NULL, +}; + +#endif + +/* ------------------------------------------------------------------ */ + +#ifdef HAVE_NXT200X +static struct nxt200x_config avertvhda180 = { + .demod_address = 0x0a, + .pll_address = 0x61, + .pll_desc = &dvb_pll_tdhu2, +}; #endif /* ------------------------------------------------------------------ */ @@ -558,7 +853,7 @@ static int dvb_init(struct saa7134_dev *dev) &dev->i2c_adap); break; case SAA7134_BOARD_PHILIPS_TOUGH: - dev->dvb.frontend = tda10046_attach(&philips_tu1216_config, + dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config, &dev->i2c_adap); break; case SAA7134_BOARD_FLYDVBTDUO: @@ -569,6 +864,31 @@ static int dvb_init(struct saa7134_dev *dev) dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config, &dev->i2c_adap); break; + case SAA7134_BOARD_PHILIPS_EUROPA: + dev->dvb.frontend = tda10046_attach(&philips_europa_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_VIDEOMATE_DVBT_300: + dev->dvb.frontend = tda10046_attach(&philips_europa_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_VIDEOMATE_DVBT_200: + dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_PHILIPS_TIGER: + dev->dvb.frontend = tda10046_attach(&philips_tiger_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_ASUSTeK_P7131_DUAL: + dev->dvb.frontend = tda10046_attach(&philips_tiger_config, + &dev->i2c_adap); + break; +#endif +#ifdef HAVE_NXT200X + case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180: + dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap); + break; #endif default: printk("%s: Huh? unknown DVB card?\n",dev->name); diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 77b627eb6483..e9ec69efb4c9 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -55,7 +55,7 @@ static void ts_reset_encoder(struct saa7134_dev* dev) saa_writeb(SAA7134_SPECIAL_MODE, 0x00); msleep(10); - saa_writeb(SAA7134_SPECIAL_MODE, 0x01); + saa_writeb(SAA7134_SPECIAL_MODE, 0x01); msleep(100); dev->empress_started = 0; } @@ -65,7 +65,7 @@ static int ts_init_encoder(struct saa7134_dev* dev) ts_reset_encoder(dev); saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL); dev->empress_started = 1; - return 0; + return 0; } /* ------------------------------------------------------------------ */ @@ -169,7 +169,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file, struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); + strcpy(cap->driver, "saa7134"); strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 711aa8e85fac..7575043f0874 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -239,7 +239,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, unsigned char data; int addr,rc,i,byte; - status = i2c_get_status(dev); + status = i2c_get_status(dev); if (!i2c_is_idle(status)) if (!i2c_reset(dev)) return -EIO; @@ -296,7 +296,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, rc = -EIO; if (!i2c_is_busy_wait(dev)) goto err; - status = i2c_get_status(dev); + status = i2c_get_status(dev); if (i2c_is_error(status)) goto err; /* ensure that the bus is idle for at least one bit slot */ @@ -335,6 +335,20 @@ static int attach_inform(struct i2c_client *client) d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->name, client->addr, client->name); + /* Am I an i2c remote control? */ + + switch (client->addr) { + case 0x7a: + case 0x47: + { + struct IR_i2c *ir = i2c_get_clientdata(client); + d1printk("%s i2c IR detected (%s).\n", + client->driver->name,ir->phys); + saa7134_set_i2c_ir(dev,ir); + break; + } + } + if (!client->driver->command) return 0; @@ -348,12 +362,12 @@ static int attach_inform(struct i2c_client *client) client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup); } - } + } if (tuner != UNSET) { - tun_setup.type = tuner; - tun_setup.addr = saa7134_boards[dev->board].tuner_addr; + tun_setup.type = tuner; + tun_setup.addr = saa7134_boards[dev->board].tuner_addr; if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { @@ -361,11 +375,11 @@ static int attach_inform(struct i2c_client *client) client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup); } - } + } client->driver->command(client, TDA9887_SET_CONFIG, &conf); - return 0; + return 0; } static struct i2c_algorithm saa7134_algo = { diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 242cb235cf92..329accda6d45 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -39,6 +39,8 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); #define dprintk(fmt, arg...) if (ir_debug) \ printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) +#define i2cdprintk(fmt, arg...) if (ir_debug) \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg) /* ---------------------------------------------------------------------- */ @@ -114,24 +116,24 @@ static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = { /* Alfons Geser <a.geser@cox.net> * updates from Job D. R. Borges <jobdrb@ig.com.br> */ static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = { - [ 18 ] = KEY_POWER, - [ 1 ] = KEY_TV, // DVR - [ 21 ] = KEY_DVD, // DVD - [ 23 ] = KEY_AUDIO, // music - // DVR mode / DVD mode / music mode - - [ 27 ] = KEY_MUTE, // mute - [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek - [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek - [ 22 ] = KEY_ZOOM, // full screen - [ 28 ] = KEY_VIDEO, // video source / eject / delall - [ 29 ] = KEY_RESTART, // playback / angle / del - [ 47 ] = KEY_SEARCH, // scan / menu / playlist - [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo - - [ 49 ] = KEY_HELP, // help - [ 50 ] = KEY_MODE, // num/memo - [ 51 ] = KEY_ESC, // cancel + [ 18 ] = KEY_POWER, + [ 1 ] = KEY_TV, // DVR + [ 21 ] = KEY_DVD, // DVD + [ 23 ] = KEY_AUDIO, // music + // DVR mode / DVD mode / music mode + + [ 27 ] = KEY_MUTE, // mute + [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek + [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek + [ 22 ] = KEY_ZOOM, // full screen + [ 28 ] = KEY_VIDEO, // video source / eject / delall + [ 29 ] = KEY_RESTART, // playback / angle / del + [ 47 ] = KEY_SEARCH, // scan / menu / playlist + [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo + + [ 49 ] = KEY_HELP, // help + [ 50 ] = KEY_MODE, // num/memo + [ 51 ] = KEY_ESC, // cancel [ 12 ] = KEY_UP, // up [ 16 ] = KEY_DOWN, // down @@ -148,24 +150,24 @@ static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = { [ 45 ] = KEY_PLAY, // play [ 46 ] = KEY_SHUFFLE, // snapshot / shuffle - [ 0 ] = KEY_KP0, - [ 5 ] = KEY_KP1, - [ 6 ] = KEY_KP2, - [ 7 ] = KEY_KP3, - [ 9 ] = KEY_KP4, - [ 10 ] = KEY_KP5, - [ 11 ] = KEY_KP6, - [ 13 ] = KEY_KP7, - [ 14 ] = KEY_KP8, - [ 15 ] = KEY_KP9, - - [ 42 ] = KEY_VOLUMEUP, - [ 17 ] = KEY_VOLUMEDOWN, - [ 24 ] = KEY_CHANNELUP, // CH.tracking up - [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down - - [ 19 ] = KEY_KPENTER, // enter - [ 33 ] = KEY_KPDOT, // . (decimal dot) + [ 0 ] = KEY_KP0, + [ 5 ] = KEY_KP1, + [ 6 ] = KEY_KP2, + [ 7 ] = KEY_KP3, + [ 9 ] = KEY_KP4, + [ 10 ] = KEY_KP5, + [ 11 ] = KEY_KP6, + [ 13 ] = KEY_KP7, + [ 14 ] = KEY_KP8, + [ 15 ] = KEY_KP9, + + [ 42 ] = KEY_VOLUMEUP, + [ 17 ] = KEY_VOLUMEDOWN, + [ 24 ] = KEY_CHANNELUP, // CH.tracking up + [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down + + [ 19 ] = KEY_KPENTER, // enter + [ 33 ] = KEY_KPDOT, // . (decimal dot) }; static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = { @@ -401,7 +403,183 @@ static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = { // 0x1d unused ? }; -/* ---------------------------------------------------------------------- */ + + +/* Mike Baikov <mike@baikov.com> */ +static IR_KEYTAB_TYPE gotview7135_codes[IR_KEYTAB_SIZE] = { + + [ 33 ] = KEY_POWER, + [ 105] = KEY_TV, + [ 51 ] = KEY_KP0, + [ 81 ] = KEY_KP1, + [ 49 ] = KEY_KP2, + [ 113] = KEY_KP3, + [ 59 ] = KEY_KP4, + [ 88 ] = KEY_KP5, + [ 65 ] = KEY_KP6, + [ 72 ] = KEY_KP7, + [ 48 ] = KEY_KP8, + [ 83 ] = KEY_KP9, + [ 115] = KEY_AGAIN, /* LOOP */ + [ 10 ] = KEY_AUDIO, + [ 97 ] = KEY_PRINT, /* PREVIEW */ + [ 122] = KEY_VIDEO, + [ 32 ] = KEY_CHANNELUP, + [ 64 ] = KEY_CHANNELDOWN, + [ 24 ] = KEY_VOLUMEDOWN, + [ 80 ] = KEY_VOLUMEUP, + [ 16 ] = KEY_MUTE, + [ 74 ] = KEY_SEARCH, + [ 123] = KEY_SHUFFLE, /* SNAPSHOT */ + [ 34 ] = KEY_RECORD, + [ 98 ] = KEY_STOP, + [ 120] = KEY_PLAY, + [ 57 ] = KEY_REWIND, + [ 89 ] = KEY_PAUSE, + [ 25 ] = KEY_FORWARD, + [ 9 ] = KEY_ZOOM, + + [ 82 ] = KEY_F21, /* LIVE TIMESHIFT */ + [ 26 ] = KEY_F22, /* MIN TIMESHIFT */ + [ 58 ] = KEY_F23, /* TIMESHIFT */ + [ 112] = KEY_F24, /* NORMAL TIMESHIFT */ +}; + +static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { + [ 0x3 ] = KEY_POWER, + [ 0x6f ] = KEY_MUTE, + [ 0x10 ] = KEY_BACKSPACE, /* Recall */ + + [ 0x11 ] = KEY_KP0, + [ 0x4 ] = KEY_KP1, + [ 0x5 ] = KEY_KP2, + [ 0x6 ] = KEY_KP3, + [ 0x8 ] = KEY_KP4, + [ 0x9 ] = KEY_KP5, + [ 0xa ] = KEY_KP6, + [ 0xc ] = KEY_KP7, + [ 0xd ] = KEY_KP8, + [ 0xe ] = KEY_KP9, + [ 0x12 ] = KEY_KPDOT, /* 100+ */ + + [ 0x7 ] = KEY_VOLUMEUP, + [ 0xb ] = KEY_VOLUMEDOWN, + [ 0x1a ] = KEY_KPPLUS, + [ 0x18 ] = KEY_KPMINUS, + [ 0x15 ] = KEY_UP, + [ 0x1d ] = KEY_DOWN, + [ 0xf ] = KEY_CHANNELUP, + [ 0x13 ] = KEY_CHANNELDOWN, + [ 0x48 ] = KEY_ZOOM, + + [ 0x1b ] = KEY_VIDEO, /* Video source */ + [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */ + [ 0x19 ] = KEY_SEARCH, /* Auto Scan */ + + [ 0x4b ] = KEY_RECORD, + [ 0x46 ] = KEY_PLAY, + [ 0x45 ] = KEY_PAUSE, /* Pause */ + [ 0x44 ] = KEY_STOP, + [ 0x40 ] = KEY_FORWARD, /* Forward ? */ + [ 0x42 ] = KEY_REWIND, /* Backward ? */ + +}; + +static IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = { + [ 0x59 ] = KEY_MUTE, + [ 0x4a ] = KEY_POWER, + + [ 0x18 ] = KEY_TEXT, + [ 0x26 ] = KEY_TV, + [ 0x3d ] = KEY_PRINT, + + [ 0x48 ] = KEY_RED, + [ 0x04 ] = KEY_GREEN, + [ 0x11 ] = KEY_YELLOW, + [ 0x00 ] = KEY_BLUE, + + [ 0x2d ] = KEY_VOLUMEUP, + [ 0x1e ] = KEY_VOLUMEDOWN, + + [ 0x49 ] = KEY_MENU, + + [ 0x16 ] = KEY_CHANNELUP, + [ 0x17 ] = KEY_CHANNELDOWN, + + [ 0x20 ] = KEY_UP, + [ 0x21 ] = KEY_DOWN, + [ 0x22 ] = KEY_LEFT, + [ 0x23 ] = KEY_RIGHT, + [ 0x0d ] = KEY_SELECT, + + + + [ 0x08 ] = KEY_BACK, + [ 0x07 ] = KEY_REFRESH, + + [ 0x2f ] = KEY_ZOOM, + [ 0x29 ] = KEY_RECORD, + + [ 0x4b ] = KEY_PAUSE, + [ 0x4d ] = KEY_REWIND, + [ 0x2e ] = KEY_PLAY, + [ 0x4e ] = KEY_FORWARD, + [ 0x53 ] = KEY_PREVIOUS, + [ 0x4c ] = KEY_STOP, + [ 0x54 ] = KEY_NEXT, + + [ 0x69 ] = KEY_KP0, + [ 0x6a ] = KEY_KP1, + [ 0x6b ] = KEY_KP2, + [ 0x6c ] = KEY_KP3, + [ 0x6d ] = KEY_KP4, + [ 0x6e ] = KEY_KP5, + [ 0x6f ] = KEY_KP6, + [ 0x70 ] = KEY_KP7, + [ 0x71 ] = KEY_KP8, + [ 0x72 ] = KEY_KP9, + + [ 0x74 ] = KEY_CHANNEL, + [ 0x0a ] = KEY_BACKSPACE, +}; + +/* Mapping for the 28 key remote control as seen at + http://www.sednacomputer.com/photo/cardbus-tv.jpg + Pavel Mihaylov <bin@bash.info> */ +static IR_KEYTAB_TYPE pctv_sedna_codes[IR_KEYTAB_SIZE] = { + [ 0 ] = KEY_KP0, + [ 1 ] = KEY_KP1, + [ 2 ] = KEY_KP2, + [ 3 ] = KEY_KP3, + [ 4 ] = KEY_KP4, + [ 5 ] = KEY_KP5, + [ 6 ] = KEY_KP6, + [ 7 ] = KEY_KP7, + [ 8 ] = KEY_KP8, + [ 9 ] = KEY_KP9, + + [ 0x0a ] = KEY_AGAIN, /* Recall */ + [ 0x0b ] = KEY_CHANNELUP, + [ 0x0c ] = KEY_VOLUMEUP, + [ 0x0d ] = KEY_MODE, /* Stereo */ + [ 0x0e ] = KEY_STOP, + [ 0x0f ] = KEY_PREVIOUSSONG, + [ 0x10 ] = KEY_ZOOM, + [ 0x11 ] = KEY_TUNER, /* Source */ + [ 0x12 ] = KEY_POWER, + [ 0x13 ] = KEY_MUTE, + [ 0x15 ] = KEY_CHANNELDOWN, + [ 0x18 ] = KEY_VOLUMEDOWN, + [ 0x19 ] = KEY_SHUFFLE, /* Snapshot */ + [ 0x1a ] = KEY_NEXTSONG, + [ 0x1b ] = KEY_TEXT, /* Time Shift */ + [ 0x1c ] = KEY_RADIO, /* FM Radio */ + [ 0x1d ] = KEY_RECORD, + [ 0x1e ] = KEY_PAUSE, +}; + + +/* -------------------- GPIO generic keycode builder -------------------- */ static int build_key(struct saa7134_dev *dev) { @@ -413,13 +591,13 @@ static int build_key(struct saa7134_dev *dev) saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN); gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); - if (ir->polling) { - if (ir->last_gpio == gpio) - return 0; - ir->last_gpio = gpio; - } + if (ir->polling) { + if (ir->last_gpio == gpio) + return 0; + ir->last_gpio = gpio; + } - data = ir_extract_bits(gpio, ir->mask_keycode); + data = ir_extract_bits(gpio, ir->mask_keycode); dprintk("build_key gpio=0x%x mask=0x%x data=%d\n", gpio, ir->mask_keycode, data); @@ -432,13 +610,87 @@ static int build_key(struct saa7134_dev *dev) return 0; } -/* ---------------------------------------------------------------------- */ +/* --------------------- Chip specific I2C key builders ----------------- */ + +static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char b; + + /* poll IR chip */ + if (1 != i2c_master_recv(&ir->c,&b,1)) { + i2cdprintk("read error\n"); + return -EIO; + } + + /* no button press */ + if (b==0) + return 0; + + /* repeating */ + if (b & 0x80) + return 1; + + *ir_key = b; + *ir_raw = b; + return 1; +} + +/* The new pinnacle PCTV remote (with the colored buttons) + * + * Ricardo Cerqueira <v4l@cerqueira.org> + */ + +static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char b[4]; + unsigned int start = 0,parity = 0,code = 0; + + /* poll IR chip */ + if (4 != i2c_master_recv(&ir->c,b,4)) { + i2cdprintk("read error\n"); + return -EIO; + } + + for (start = 0; start<4; start++) { + if (b[start] == 0x80) { + code=b[(start+3)%4]; + parity=b[(start+2)%4]; + } + } + + /* Empty Request */ + if (parity==0) + return 0; + + /* Repeating... */ + if (ir->old == parity) + return 0; + + + ir->old = parity; + + /* Reduce code value to fit inside IR_KEYTAB_SIZE + * + * this is the only value that results in 42 unique + * codes < 128 + */ + + code %= 0x88; + + *ir_raw = code; + *ir_key = code; + + i2cdprintk("Pinnacle PCTV key %02x\n", code); + + return 1; +} + void saa7134_input_irq(struct saa7134_dev *dev) { - struct saa7134_ir *ir = dev->remote; + struct saa7134_ir *ir = dev->remote; - if (!ir->polling) + if (!ir->polling) build_key(dev); } @@ -464,7 +716,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) int polling = 0; int ir_type = IR_TYPE_OTHER; - if (!dev->has_remote) + if (dev->has_remote != SAA7134_REMOTE_GPIO) return -ENODEV; if (disable_ir) return -ENODEV; @@ -473,7 +725,8 @@ int saa7134_input_init1(struct saa7134_dev *dev) switch (dev->board) { case SAA7134_BOARD_FLYVIDEO2000: case SAA7134_BOARD_FLYVIDEO3000: - case SAA7134_BOARD_FLYTVPLATINUM_FM: + case SAA7134_BOARD_FLYTVPLATINUM_FM: + case SAA7134_BOARD_FLYTVPLATINUM_MINI2: ir_codes = flyvideo_codes; mask_keycode = 0xEC00000; mask_keydown = 0x0040000; @@ -514,14 +767,33 @@ int saa7134_input_init1(struct saa7134_dev *dev) saa_setb(SAA7134_GPIO_GPMODE0, 0x4); saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); break; + case SAA7134_BOARD_KWORLD_TERMINATOR: + ir_codes = avacssmart_codes; + mask_keycode = 0x00001f; + mask_keyup = 0x000060; + polling = 50; // ms + break; case SAA7134_BOARD_MANLI_MTV001: case SAA7134_BOARD_MANLI_MTV002: + case SAA7134_BOARD_BEHOLD_409FM: ir_codes = manli_codes; mask_keycode = 0x001f00; mask_keyup = 0x004000; - mask_keydown = 0x002000; polling = 50; // ms break; + case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: + ir_codes = pctv_sedna_codes; + mask_keycode = 0x001f00; + mask_keyup = 0x004000; + polling = 50; // ms + break; + case SAA7134_BOARD_GOTVIEW_7135: + ir_codes = gotview7135_codes; + mask_keycode = 0x0003EC; + mask_keyup = 0x008000; + mask_keydown = 0x000010; + polling = 50; // ms + break; case SAA7134_BOARD_VIDEOMATE_TV_PVR: case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: ir_codes = videomate_tv_pvr_codes; @@ -529,6 +801,12 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keyup = 0x400000; polling = 50; // ms break; + case SAA7134_BOARD_VIDEOMATE_DVBT_300: + case SAA7134_BOARD_VIDEOMATE_DVBT_200: + ir_codes = videomate_tv_pvr_codes; + mask_keycode = 0x003F00; + mask_keyup = 0x040000; + break; } if (NULL == ir_codes) { printk("%s: Oops: IR config error [card=%d]\n", @@ -548,7 +826,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) ir->mask_keycode = mask_keycode; ir->mask_keydown = mask_keydown; ir->mask_keyup = mask_keyup; - ir->polling = polling; + ir->polling = polling; /* init input device */ snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)", @@ -596,6 +874,31 @@ void saa7134_input_fini(struct saa7134_dev *dev) dev->remote = NULL; } +void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) +{ + if (disable_ir) { + dprintk("Found supported i2c remote, but IR has been disabled\n"); + ir->get_key=NULL; + return; + } + + switch (dev->board) { + case SAA7134_BOARD_PINNACLE_PCTV_110i: + snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV"); + ir->get_key = get_key_pinnacle; + ir->ir_codes = ir_codes_pinnacle; + break; + case SAA7134_BOARD_UPMOST_PURPLE_TV: + snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV"); + ir->get_key = get_key_purpletv; + ir->ir_codes = ir_codes_purpletv; + break; + default: + dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board); + break; + } + +} /* ---------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index c20630c82f1c..fd53dfcc1644 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -44,6 +44,7 @@ MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)"); #define dprintk(fmt, arg...) if (oss_debug) \ printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg) + /* ------------------------------------------------------------------ */ static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks) @@ -58,12 +59,12 @@ static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks) if ((blksize * blocks) > 1024*1024) blocks = 1024*1024 / blksize; - dev->oss.blocks = blocks; - dev->oss.blksize = blksize; - dev->oss.bufsize = blksize * blocks; + dev->dmasound.blocks = blocks; + dev->dmasound.blksize = blksize; + dev->dmasound.bufsize = blksize * blocks; dprintk("buffer config: %d blocks / %d bytes, %d kB total\n", - blocks,blksize,blksize * blocks / 1024); + blocks,blksize,blksize * blocks / 1024); return 0; } @@ -71,11 +72,11 @@ static int dsp_buffer_init(struct saa7134_dev *dev) { int err; - if (!dev->oss.bufsize) + if (!dev->dmasound.bufsize) BUG(); - videobuf_dma_init(&dev->oss.dma); - err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE, - (dev->oss.bufsize + PAGE_SIZE) >> PAGE_SHIFT); + videobuf_dma_init(&dev->dmasound.dma); + err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE, + (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); if (0 != err) return err; return 0; @@ -83,26 +84,26 @@ static int dsp_buffer_init(struct saa7134_dev *dev) static int dsp_buffer_free(struct saa7134_dev *dev) { - if (!dev->oss.blksize) + if (!dev->dmasound.blksize) BUG(); - videobuf_dma_free(&dev->oss.dma); - dev->oss.blocks = 0; - dev->oss.blksize = 0; - dev->oss.bufsize = 0; + videobuf_dma_free(&dev->dmasound.dma); + dev->dmasound.blocks = 0; + dev->dmasound.blksize = 0; + dev->dmasound.bufsize = 0; return 0; } static void dsp_dma_start(struct saa7134_dev *dev) { - dev->oss.dma_blk = 0; - dev->oss.dma_running = 1; + dev->dmasound.dma_blk = 0; + dev->dmasound.dma_running = 1; saa7134_set_dmabits(dev); } static void dsp_dma_stop(struct saa7134_dev *dev) { - dev->oss.dma_blk = -1; - dev->oss.dma_running = 0; + dev->dmasound.dma_blk = -1; + dev->dmasound.dma_running = 0; saa7134_set_dmabits(dev); } @@ -113,18 +114,18 @@ static int dsp_rec_start(struct saa7134_dev *dev) unsigned long flags; /* prepare buffer */ - if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma))) + if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma))) return err; - if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->oss.pt))) + if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) goto fail1; - if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->oss.pt, - dev->oss.dma.sglist, - dev->oss.dma.sglen, + if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt, + dev->dmasound.dma.sglist, + dev->dmasound.dma.sglen, 0))) goto fail2; /* sample format */ - switch (dev->oss.afmt) { + switch (dev->dmasound.afmt) { case AFMT_U8: case AFMT_S8: fmt = 0x00; break; case AFMT_U16_LE: @@ -136,14 +137,14 @@ static int dsp_rec_start(struct saa7134_dev *dev) goto fail2; } - switch (dev->oss.afmt) { + switch (dev->dmasound.afmt) { case AFMT_S8: case AFMT_S16_LE: case AFMT_S16_BE: sign = 1; break; default: sign = 0; break; } - switch (dev->oss.afmt) { + switch (dev->dmasound.afmt) { case AFMT_U16_BE: case AFMT_S16_BE: bswap = 1; break; default: bswap = 0; break; @@ -151,58 +152,58 @@ static int dsp_rec_start(struct saa7134_dev *dev) switch (dev->pci->device) { case PCI_DEVICE_ID_PHILIPS_SAA7134: - if (1 == dev->oss.channels) + if (1 == dev->dmasound.channels) fmt |= (1 << 3); - if (2 == dev->oss.channels) + if (2 == dev->dmasound.channels) fmt |= (3 << 3); if (sign) fmt |= 0x04; - fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80; + fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80; - saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->oss.blksize - 1) & 0x0000ff)); - saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->oss.blksize - 1) & 0x00ff00) >> 8); - saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->oss.blksize - 1) & 0xff0000) >> 16); + saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff)); + saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8); + saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16); saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt); break; case PCI_DEVICE_ID_PHILIPS_SAA7133: case PCI_DEVICE_ID_PHILIPS_SAA7135: - if (1 == dev->oss.channels) + if (1 == dev->dmasound.channels) fmt |= (1 << 4); - if (2 == dev->oss.channels) + if (2 == dev->dmasound.channels) fmt |= (2 << 4); if (!sign) fmt |= 0x04; - saa_writel(0x588 >> 2, dev->oss.blksize -4); - saa_writel(0x58c >> 2, 0x543210 | (fmt << 24)); + saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4); + saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24)); break; } dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", - dev->oss.afmt, dev->oss.channels, fmt, + dev->dmasound.afmt, dev->dmasound.channels, fmt, bswap ? 'b' : '-'); /* dma: setup channel 6 (= AUDIO) */ control = SAA7134_RS_CONTROL_BURST_16 | SAA7134_RS_CONTROL_ME | - (dev->oss.pt.dma >> 12); + (dev->dmasound.pt.dma >> 12); if (bswap) control |= SAA7134_RS_CONTROL_BSWAP; saa_writel(SAA7134_RS_BA1(6),0); - saa_writel(SAA7134_RS_BA2(6),dev->oss.blksize); + saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize); saa_writel(SAA7134_RS_PITCH(6),0); saa_writel(SAA7134_RS_CONTROL(6),control); /* start dma */ - dev->oss.recording_on = 1; + dev->dmasound.recording_on = 1; spin_lock_irqsave(&dev->slock,flags); dsp_dma_start(dev); spin_unlock_irqrestore(&dev->slock,flags); return 0; fail2: - saa7134_pgtable_free(dev->pci,&dev->oss.pt); + saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); fail1: - videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma); + videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma); return err; } @@ -210,17 +211,17 @@ static int dsp_rec_stop(struct saa7134_dev *dev) { unsigned long flags; - dprintk("rec_stop dma_blk=%d\n",dev->oss.dma_blk); + dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk); /* stop dma */ - dev->oss.recording_on = 0; + dev->dmasound.recording_on = 0; spin_lock_irqsave(&dev->slock,flags); dsp_dma_stop(dev); spin_unlock_irqrestore(&dev->slock,flags); /* unlock buffer */ - saa7134_pgtable_free(dev->pci,&dev->oss.pt); - videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma); + saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); + videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma); return 0; } @@ -235,35 +236,35 @@ static int dsp_open(struct inode *inode, struct file *file) list_for_each(list,&saa7134_devlist) { h = list_entry(list, struct saa7134_dev, devlist); - if (h->oss.minor_dsp == minor) + if (h->dmasound.minor_dsp == minor) dev = h; } if (NULL == dev) return -ENODEV; - down(&dev->oss.lock); + down(&dev->dmasound.lock); err = -EBUSY; - if (dev->oss.users_dsp) + if (dev->dmasound.users_dsp) goto fail1; - dev->oss.users_dsp++; + dev->dmasound.users_dsp++; file->private_data = dev; - dev->oss.afmt = AFMT_U8; - dev->oss.channels = 1; - dev->oss.read_count = 0; - dev->oss.read_offset = 0; + dev->dmasound.afmt = AFMT_U8; + dev->dmasound.channels = 1; + dev->dmasound.read_count = 0; + dev->dmasound.read_offset = 0; dsp_buffer_conf(dev,PAGE_SIZE,64); err = dsp_buffer_init(dev); if (0 != err) goto fail2; - up(&dev->oss.lock); + up(&dev->dmasound.lock); return 0; fail2: - dev->oss.users_dsp--; + dev->dmasound.users_dsp--; fail1: - up(&dev->oss.lock); + up(&dev->dmasound.lock); return err; } @@ -271,13 +272,13 @@ static int dsp_release(struct inode *inode, struct file *file) { struct saa7134_dev *dev = file->private_data; - down(&dev->oss.lock); - if (dev->oss.recording_on) + down(&dev->dmasound.lock); + if (dev->dmasound.recording_on) dsp_rec_stop(dev); dsp_buffer_free(dev); - dev->oss.users_dsp--; + dev->dmasound.users_dsp--; file->private_data = NULL; - up(&dev->oss.lock); + up(&dev->dmasound.lock); return 0; } @@ -290,12 +291,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer, unsigned long flags; int err,ret = 0; - add_wait_queue(&dev->oss.wq, &wait); - down(&dev->oss.lock); + add_wait_queue(&dev->dmasound.wq, &wait); + down(&dev->dmasound.lock); while (count > 0) { /* wait for data if needed */ - if (0 == dev->oss.read_count) { - if (!dev->oss.recording_on) { + if (0 == dev->dmasound.read_count) { + if (!dev->dmasound.recording_on) { err = dsp_rec_start(dev); if (err < 0) { if (0 == ret) @@ -303,8 +304,8 @@ static ssize_t dsp_read(struct file *file, char __user *buffer, break; } } - if (dev->oss.recording_on && - !dev->oss.dma_running) { + if (dev->dmasound.recording_on && + !dev->dmasound.dma_running) { /* recover from overruns */ spin_lock_irqsave(&dev->slock,flags); dsp_dma_start(dev); @@ -315,12 +316,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer, ret = -EAGAIN; break; } - up(&dev->oss.lock); + up(&dev->dmasound.lock); set_current_state(TASK_INTERRUPTIBLE); - if (0 == dev->oss.read_count) + if (0 == dev->dmasound.read_count) schedule(); set_current_state(TASK_RUNNING); - down(&dev->oss.lock); + down(&dev->dmasound.lock); if (signal_pending(current)) { if (0 == ret) ret = -EINTR; @@ -330,12 +331,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer, /* copy data to userspace */ bytes = count; - if (bytes > dev->oss.read_count) - bytes = dev->oss.read_count; - if (bytes > dev->oss.bufsize - dev->oss.read_offset) - bytes = dev->oss.bufsize - dev->oss.read_offset; + if (bytes > dev->dmasound.read_count) + bytes = dev->dmasound.read_count; + if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset) + bytes = dev->dmasound.bufsize - dev->dmasound.read_offset; if (copy_to_user(buffer + ret, - dev->oss.dma.vmalloc + dev->oss.read_offset, + dev->dmasound.dma.vmalloc + dev->dmasound.read_offset, bytes)) { if (0 == ret) ret = -EFAULT; @@ -344,13 +345,13 @@ static ssize_t dsp_read(struct file *file, char __user *buffer, ret += bytes; count -= bytes; - dev->oss.read_count -= bytes; - dev->oss.read_offset += bytes; - if (dev->oss.read_offset == dev->oss.bufsize) - dev->oss.read_offset = 0; + dev->dmasound.read_count -= bytes; + dev->dmasound.read_offset += bytes; + if (dev->dmasound.read_offset == dev->dmasound.bufsize) + dev->dmasound.read_offset = 0; } - up(&dev->oss.lock); - remove_wait_queue(&dev->oss.wq, &wait); + up(&dev->dmasound.lock); + remove_wait_queue(&dev->dmasound.wq, &wait); return ret; } @@ -370,53 +371,53 @@ static int dsp_ioctl(struct inode *inode, struct file *file, if (oss_debug > 1) saa7134_print_ioctl(dev->name,cmd); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - case SNDCTL_DSP_GETCAPS: + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, p); + case SNDCTL_DSP_GETCAPS: return 0; - case SNDCTL_DSP_SPEED: + case SNDCTL_DSP_SPEED: if (get_user(val, p)) return -EFAULT; /* fall through */ - case SOUND_PCM_READ_RATE: - return put_user(dev->oss.rate, p); + case SOUND_PCM_READ_RATE: + return put_user(dev->dmasound.rate, p); - case SNDCTL_DSP_STEREO: + case SNDCTL_DSP_STEREO: if (get_user(val, p)) return -EFAULT; - down(&dev->oss.lock); - dev->oss.channels = val ? 2 : 1; - if (dev->oss.recording_on) { + down(&dev->dmasound.lock); + dev->dmasound.channels = val ? 2 : 1; + if (dev->dmasound.recording_on) { dsp_rec_stop(dev); dsp_rec_start(dev); } - up(&dev->oss.lock); - return put_user(dev->oss.channels-1, p); + up(&dev->dmasound.lock); + return put_user(dev->dmasound.channels-1, p); - case SNDCTL_DSP_CHANNELS: + case SNDCTL_DSP_CHANNELS: if (get_user(val, p)) return -EFAULT; if (val != 1 && val != 2) return -EINVAL; - down(&dev->oss.lock); - dev->oss.channels = val; - if (dev->oss.recording_on) { + down(&dev->dmasound.lock); + dev->dmasound.channels = val; + if (dev->dmasound.recording_on) { dsp_rec_stop(dev); dsp_rec_start(dev); } - up(&dev->oss.lock); + up(&dev->dmasound.lock); /* fall through */ - case SOUND_PCM_READ_CHANNELS: - return put_user(dev->oss.channels, p); + case SOUND_PCM_READ_CHANNELS: + return put_user(dev->dmasound.channels, p); - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ return put_user(AFMT_U8 | AFMT_S8 | AFMT_U16_LE | AFMT_U16_BE | AFMT_S16_LE | AFMT_S16_BE, p); - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ if (get_user(val, p)) return -EFAULT; switch (val) { @@ -429,20 +430,20 @@ static int dsp_ioctl(struct inode *inode, struct file *file, case AFMT_U16_BE: case AFMT_S16_LE: case AFMT_S16_BE: - down(&dev->oss.lock); - dev->oss.afmt = val; - if (dev->oss.recording_on) { + down(&dev->dmasound.lock); + dev->dmasound.afmt = val; + if (dev->dmasound.recording_on) { dsp_rec_stop(dev); dsp_rec_start(dev); } - up(&dev->oss.lock); - return put_user(dev->oss.afmt, p); + up(&dev->dmasound.lock); + return put_user(dev->dmasound.afmt, p); default: return -EINVAL; } - case SOUND_PCM_READ_BITS: - switch (dev->oss.afmt) { + case SOUND_PCM_READ_BITS: + switch (dev->dmasound.afmt) { case AFMT_U8: case AFMT_S8: return put_user(8, p); @@ -455,23 +456,23 @@ static int dsp_ioctl(struct inode *inode, struct file *file, return -EINVAL; } - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; - case SNDCTL_DSP_RESET: - down(&dev->oss.lock); - if (dev->oss.recording_on) + case SNDCTL_DSP_RESET: + down(&dev->dmasound.lock); + if (dev->dmasound.recording_on) dsp_rec_stop(dev); - up(&dev->oss.lock); + up(&dev->dmasound.lock); return 0; - case SNDCTL_DSP_GETBLKSIZE: - return put_user(dev->oss.blksize, p); + case SNDCTL_DSP_GETBLKSIZE: + return put_user(dev->dmasound.blksize, p); - case SNDCTL_DSP_SETFRAGMENT: + case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, p)) return -EFAULT; - if (dev->oss.recording_on) + if (dev->dmasound.recording_on) return -EBUSY; dsp_buffer_free(dev); /* used to be arg >> 16 instead of val >> 16; fixed */ @@ -479,16 +480,16 @@ static int dsp_ioctl(struct inode *inode, struct file *file, dsp_buffer_init(dev); return 0; - case SNDCTL_DSP_SYNC: + case SNDCTL_DSP_SYNC: /* NOP */ return 0; case SNDCTL_DSP_GETISPACE: { audio_buf_info info; - info.fragsize = dev->oss.blksize; - info.fragstotal = dev->oss.blocks; - info.bytes = dev->oss.read_count; + info.fragsize = dev->dmasound.blksize; + info.fragstotal = dev->dmasound.blocks; + info.bytes = dev->dmasound.read_count; info.fragments = info.bytes / info.fragsize; if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; @@ -504,13 +505,13 @@ static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait) struct saa7134_dev *dev = file->private_data; unsigned int mask = 0; - poll_wait(file, &dev->oss.wq, wait); + poll_wait(file, &dev->dmasound.wq, wait); - if (0 == dev->oss.read_count) { - down(&dev->oss.lock); - if (!dev->oss.recording_on) + if (0 == dev->dmasound.read_count) { + down(&dev->dmasound.lock); + if (!dev->dmasound.recording_on) dsp_rec_start(dev); - up(&dev->oss.lock); + up(&dev->dmasound.lock); } else mask |= (POLLIN | POLLRDNORM); return mask; @@ -534,7 +535,7 @@ mixer_recsrc_7134(struct saa7134_dev *dev) { int analog_io,rate; - switch (dev->oss.input) { + switch (dev->dmasound.input) { case TV: saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0); saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00); @@ -542,8 +543,8 @@ mixer_recsrc_7134(struct saa7134_dev *dev) case LINE1: case LINE2: case LINE2_LEFT: - analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08; - rate = (32000 == dev->oss.rate) ? 0x01 : 0x03; + analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08; + rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03; saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io); saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80); saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate); @@ -559,10 +560,10 @@ mixer_recsrc_7133(struct saa7134_dev *dev) xbarin = 0x03; // adc anabar = 0; - switch (dev->oss.input) { + switch (dev->dmasound.input) { case TV: xbarin = 0; // Demodulator - anabar = 2; // DACs + anabar = 2; // DACs break; case LINE1: anabar = 0; // aux1, aux1 @@ -585,9 +586,9 @@ mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src) { static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" }; - dev->oss.count++; - dev->oss.input = src; - dprintk("mixer input = %s\n",iname[dev->oss.input]); + dev->dmasound.count++; + dev->dmasound.input = src; + dprintk("mixer input = %s\n",iname[dev->dmasound.input]); switch (dev->pci->device) { case PCI_DEVICE_ID_PHILIPS_SAA7134: @@ -639,7 +640,7 @@ static int mixer_open(struct inode *inode, struct file *file) list_for_each(list,&saa7134_devlist) { h = list_entry(list, struct saa7134_dev, devlist); - if (h->oss.minor_mixer == minor) + if (h->dmasound.minor_mixer == minor) dev = h; } if (NULL == dev) @@ -666,28 +667,28 @@ static int mixer_ioctl(struct inode *inode, struct file *file, if (oss_debug > 1) saa7134_print_ioctl(dev->name,cmd); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, p); case SOUND_MIXER_INFO: { mixer_info info; memset(&info,0,sizeof(info)); - strlcpy(info.id, "TV audio", sizeof(info.id)); - strlcpy(info.name, dev->name, sizeof(info.name)); - info.modify_counter = dev->oss.count; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; + strlcpy(info.id, "TV audio", sizeof(info.id)); + strlcpy(info.name, dev->name, sizeof(info.name)); + info.modify_counter = dev->dmasound.count; + if (copy_to_user(argp, &info, sizeof(info))) + return -EFAULT; return 0; } case SOUND_OLD_MIXER_INFO: { _old_mixer_info info; memset(&info,0,sizeof(info)); - strlcpy(info.id, "TV audio", sizeof(info.id)); - strlcpy(info.name, dev->name, sizeof(info.name)); - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; + strlcpy(info.id, "TV audio", sizeof(info.id)); + strlcpy(info.name, dev->name, sizeof(info.name)); + if (copy_to_user(argp, &info, sizeof(info))) + return -EFAULT; return 0; } case MIXER_READ(SOUND_MIXER_CAPS): @@ -697,26 +698,26 @@ static int mixer_ioctl(struct inode *inode, struct file *file, case MIXER_READ(SOUND_MIXER_RECMASK): case MIXER_READ(SOUND_MIXER_DEVMASK): val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2; - if (32000 == dev->oss.rate) + if (32000 == dev->dmasound.rate) val |= SOUND_MASK_VIDEO; return put_user(val, p); case MIXER_WRITE(SOUND_MIXER_RECSRC): if (get_user(val, p)) return -EFAULT; - input = dev->oss.input; - if (32000 == dev->oss.rate && - val & SOUND_MASK_VIDEO && dev->oss.input != TV) + input = dev->dmasound.input; + if (32000 == dev->dmasound.rate && + val & SOUND_MASK_VIDEO && dev->dmasound.input != TV) input = TV; - if (val & SOUND_MASK_LINE1 && dev->oss.input != LINE1) + if (val & SOUND_MASK_LINE1 && dev->dmasound.input != LINE1) input = LINE1; - if (val & SOUND_MASK_LINE2 && dev->oss.input != LINE2) + if (val & SOUND_MASK_LINE2 && dev->dmasound.input != LINE2) input = LINE2; - if (input != dev->oss.input) + if (input != dev->dmasound.input) mixer_recsrc(dev,input); /* fall throuth */ case MIXER_READ(SOUND_MIXER_RECSRC): - switch (dev->oss.input) { + switch (dev->dmasound.input) { case TV: ret = SOUND_MASK_VIDEO; break; case LINE1: ret = SOUND_MASK_LINE1; break; case LINE2: ret = SOUND_MASK_LINE2; break; @@ -726,7 +727,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file, case MIXER_WRITE(SOUND_MIXER_VIDEO): case MIXER_READ(SOUND_MIXER_VIDEO): - if (32000 != dev->oss.rate) + if (32000 != dev->dmasound.rate) return -EINVAL; return put_user(100 | 100 << 8, p); @@ -735,22 +736,22 @@ static int mixer_ioctl(struct inode *inode, struct file *file, return -EFAULT; val &= 0xff; val = (val <= 50) ? 50 : 100; - dev->oss.line1 = val; - mixer_level(dev,LINE1,dev->oss.line1); + dev->dmasound.line1 = val; + mixer_level(dev,LINE1,dev->dmasound.line1); /* fall throuth */ case MIXER_READ(SOUND_MIXER_LINE1): - return put_user(dev->oss.line1 | dev->oss.line1 << 8, p); + return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p); case MIXER_WRITE(SOUND_MIXER_LINE2): if (get_user(val, p)) return -EFAULT; val &= 0xff; val = (val <= 50) ? 50 : 100; - dev->oss.line2 = val; - mixer_level(dev,LINE2,dev->oss.line2); + dev->dmasound.line2 = val; + mixer_level(dev,LINE2,dev->dmasound.line2); /* fall throuth */ case MIXER_READ(SOUND_MIXER_LINE2): - return put_user(dev->oss.line2 | dev->oss.line2 << 8, p); + return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p); default: return -EINVAL; @@ -770,8 +771,8 @@ struct file_operations saa7134_mixer_fops = { int saa7134_oss_init1(struct saa7134_dev *dev) { /* general */ - init_MUTEX(&dev->oss.lock); - init_waitqueue_head(&dev->oss.wq); + init_MUTEX(&dev->dmasound.lock); + init_waitqueue_head(&dev->dmasound.wq); switch (dev->pci->device) { case PCI_DEVICE_ID_PHILIPS_SAA7133: @@ -783,17 +784,17 @@ int saa7134_oss_init1(struct saa7134_dev *dev) } /* dsp */ - dev->oss.rate = 32000; + dev->dmasound.rate = 32000; if (oss_rate) - dev->oss.rate = oss_rate; - dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000; + dev->dmasound.rate = oss_rate; + dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000; /* mixer */ - dev->oss.line1 = 50; - dev->oss.line2 = 50; - mixer_level(dev,LINE1,dev->oss.line1); - mixer_level(dev,LINE2,dev->oss.line2); - mixer_recsrc(dev, (dev->oss.rate == 32000) ? TV : LINE2); + dev->dmasound.line1 = 50; + dev->dmasound.line2 = 50; + mixer_level(dev,LINE1,dev->dmasound.line1); + mixer_level(dev,LINE2,dev->dmasound.line2); + mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2); return 0; } @@ -809,7 +810,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) int next_blk, reg = 0; spin_lock(&dev->slock); - if (UNSET == dev->oss.dma_blk) { + if (UNSET == dev->dmasound.dma_blk) { dprintk("irq: recording stopped\n"); goto done; } @@ -817,11 +818,11 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) dprintk("irq: lost %ld\n", (status >> 24) & 0x0f); if (0 == (status & 0x10000000)) { /* odd */ - if (0 == (dev->oss.dma_blk & 0x01)) + if (0 == (dev->dmasound.dma_blk & 0x01)) reg = SAA7134_RS_BA1(6); } else { /* even */ - if (1 == (dev->oss.dma_blk & 0x01)) + if (1 == (dev->dmasound.dma_blk & 0x01)) reg = SAA7134_RS_BA2(6); } if (0 == reg) { @@ -829,25 +830,25 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) (status & 0x10000000) ? "even" : "odd"); goto done; } - if (dev->oss.read_count >= dev->oss.blksize * (dev->oss.blocks-2)) { - dprintk("irq: overrun [full=%d/%d]\n",dev->oss.read_count, - dev->oss.bufsize); + if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { + dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count, + dev->dmasound.bufsize); dsp_dma_stop(dev); goto done; } /* next block addr */ - next_blk = (dev->oss.dma_blk + 2) % dev->oss.blocks; - saa_writel(reg,next_blk * dev->oss.blksize); + next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; + saa_writel(reg,next_blk * dev->dmasound.blksize); if (oss_debug > 2) dprintk("irq: ok, %s, next_blk=%d, addr=%x\n", (status & 0x10000000) ? "even" : "odd ", next_blk, - next_blk * dev->oss.blksize); + next_blk * dev->dmasound.blksize); /* update status & wake waiting readers */ - dev->oss.dma_blk = (dev->oss.dma_blk + 1) % dev->oss.blocks; - dev->oss.read_count += dev->oss.blksize; - wake_up(&dev->oss.wq); + dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks; + dev->dmasound.read_count += dev->dmasound.blksize; + wake_up(&dev->dmasound.wq); done: spin_unlock(&dev->slock); diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h index ae0c7a165390..ac6431ba4fc3 100644 --- a/drivers/media/video/saa7134/saa7134-reg.h +++ b/drivers/media/video/saa7134/saa7134-reg.h @@ -27,7 +27,7 @@ /* DMA channels, n = 0 ... 6 */ #define SAA7134_RS_BA1(n) ((0x200 >> 2) + 4*n) -#define SAA7134_RS_BA2(n) ((0x204 >> 2) + 4*n) +#define SAA7134_RS_BA2(n) ((0x204 >> 2) + 4*n) #define SAA7134_RS_PITCH(n) ((0x208 >> 2) + 4*n) #define SAA7134_RS_CONTROL(n) ((0x20c >> 2) + 4*n) #define SAA7134_RS_CONTROL_WSWAP (0x01 << 25) @@ -43,16 +43,24 @@ #define SAA7134_FIFO_SIZE (0x2a0 >> 2) #define SAA7134_THRESHOULD (0x2a4 >> 2) +#define SAA7133_NUM_SAMPLES (0x588 >> 2) +#define SAA7133_AUDIO_CHANNEL (0x58c >> 2) +#define SAA7133_AUDIO_FORMAT (0x58f >> 2) +#define SAA7133_DIGITAL_OUTPUT_SEL1 (0x46c >> 2) +#define SAA7133_DIGITAL_OUTPUT_SEL2 (0x470 >> 2) +#define SAA7133_DIGITAL_INPUT_XBAR1 (0x464 >> 2) +#define SAA7133_ANALOG_IO_SELECT (0x594 >> 2) + /* main control */ #define SAA7134_MAIN_CTRL (0x2a8 >> 2) -#define SAA7134_MAIN_CTRL_VPLLE (1 << 15) -#define SAA7134_MAIN_CTRL_APLLE (1 << 14) -#define SAA7134_MAIN_CTRL_EXOSC (1 << 13) -#define SAA7134_MAIN_CTRL_EVFE1 (1 << 12) -#define SAA7134_MAIN_CTRL_EVFE2 (1 << 11) -#define SAA7134_MAIN_CTRL_ESFE (1 << 10) -#define SAA7134_MAIN_CTRL_EBADC (1 << 9) -#define SAA7134_MAIN_CTRL_EBDAC (1 << 8) +#define SAA7134_MAIN_CTRL_VPLLE (1 << 15) +#define SAA7134_MAIN_CTRL_APLLE (1 << 14) +#define SAA7134_MAIN_CTRL_EXOSC (1 << 13) +#define SAA7134_MAIN_CTRL_EVFE1 (1 << 12) +#define SAA7134_MAIN_CTRL_EVFE2 (1 << 11) +#define SAA7134_MAIN_CTRL_ESFE (1 << 10) +#define SAA7134_MAIN_CTRL_EBADC (1 << 9) +#define SAA7134_MAIN_CTRL_EBDAC (1 << 8) #define SAA7134_MAIN_CTRL_TE6 (1 << 6) #define SAA7134_MAIN_CTRL_TE5 (1 << 5) #define SAA7134_MAIN_CTRL_TE4 (1 << 4) @@ -348,6 +356,7 @@ /* test modes */ #define SAA7134_SPECIAL_MODE 0x1d0 +#define SAA7134_PRODUCTION_TEST_MODE 0x1d1 /* audio -- saa7133 + saa7135 only */ #define SAA7135_DSP_RWSTATE 0x580 diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 463885601ab4..470903e2f5e5 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -46,17 +46,11 @@ static int buffer_activate(struct saa7134_dev *dev, struct saa7134_buf *buf, struct saa7134_buf *next) { - u32 control; dprintk("buffer_activate [%p]",buf); buf->vb.state = STATE_ACTIVE; buf->top_seen = 0; - /* dma: setup channel 5 (= TS) */ - control = SAA7134_RS_CONTROL_BURST_16 | - SAA7134_RS_CONTROL_ME | - (buf->pt->dma >> 12); - if (NULL == next) next = buf; if (V4L2_FIELD_TOP == buf->vb.field) { @@ -68,8 +62,6 @@ static int buffer_activate(struct saa7134_dev *dev, saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next)); saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf)); } - saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE); - saa_writel(SAA7134_RS_CONTROL(5),control); /* start DMA */ saa7134_set_dmabits(dev); @@ -84,6 +76,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct saa7134_dev *dev = q->priv_data; struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); unsigned int lines, llength, size; + u32 control; int err; dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]); @@ -115,6 +108,18 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (err) goto oops; } + + /* dma: setup channel 5 (= TS) */ + control = SAA7134_RS_CONTROL_BURST_16 | + SAA7134_RS_CONTROL_ME | + (buf->pt->dma >> 12); + + saa_writeb(SAA7134_TS_DMA0, ((lines-1)&0xff)); + saa_writeb(SAA7134_TS_DMA1, (((lines-1)>>8)&0xff)); + saa_writeb(SAA7134_TS_DMA2, ((((lines-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */ + saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE); + saa_writel(SAA7134_RS_CONTROL(5),control); + buf->vb.state = STATE_PREPARED; buf->activate = buffer_activate; buf->vb.field = field; @@ -164,11 +169,11 @@ EXPORT_SYMBOL_GPL(saa7134_ts_qops); /* ----------------------------------------------------------- */ /* exported stuff */ -static unsigned int tsbufs = 4; +static unsigned int tsbufs = 8; module_param(tsbufs, int, 0444); MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32"); -static unsigned int ts_nr_packets = 30; +static unsigned int ts_nr_packets = 64; module_param(ts_nr_packets, int, 0444); MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)"); @@ -220,10 +225,10 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) if (dev->ts_q.curr) { field = dev->ts_q.curr->vb.field; if (field == V4L2_FIELD_TOP) { - if ((status & 0x100000) != 0x100000) + if ((status & 0x100000) != 0x000000) goto done; } else { - if ((status & 0x100000) != 0x000000) + if ((status & 0x100000) != 0x100000) goto done; } saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE); diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 61a2d6b50eef..93268427750d 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -207,6 +207,10 @@ static void tvaudio_setcarrier(struct saa7134_dev *dev, saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary)); } +#define SAA7134_MUTE_MASK 0xbb +#define SAA7134_MUTE_ANALOG 0x04 +#define SAA7134_MUTE_I2S 0x40 + static void mute_input_7134(struct saa7134_dev *dev) { unsigned int mute; @@ -241,7 +245,11 @@ static void mute_input_7134(struct saa7134_dev *dev) if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device) /* 7134 mute */ - saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xbf : 0xbb); + saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? + SAA7134_MUTE_MASK | + SAA7134_MUTE_ANALOG | + SAA7134_MUTE_I2S : + SAA7134_MUTE_MASK); /* switch internal audio mux */ switch (in->amux) { @@ -753,17 +761,17 @@ static int mute_input_7133(struct saa7134_dev *dev) /* switch gpio-connected external audio mux */ - if (0 != card(dev).gpiomask) { - mask = card(dev).gpiomask; + if (0 != card(dev).gpiomask) { + mask = card(dev).gpiomask; if (card(dev).mute.name && dev->ctl_mute) in = &card(dev).mute; else in = dev->input; - saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); - saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio); - saa7134_track_gpio(dev,in->name); + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio); + saa7134_track_gpio(dev,in->name); } return 0; @@ -1016,9 +1024,12 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev) return 0; } +EXPORT_SYMBOL(saa_dsp_writel); + /* ----------------------------------------------------------- */ /* * Local variables: * c-basic-offset: 8 * End: */ + diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 35e5e85f669a..45c852df13ed 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -30,6 +30,9 @@ #include "saa7134-reg.h" #include "saa7134.h" +/* Include V4L1 specific functions. Should be removed soon */ +#include <linux/videodev.h> + /* ------------------------------------------------------------------ */ static unsigned int video_debug = 0; @@ -48,6 +51,43 @@ MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced"); printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) /* ------------------------------------------------------------------ */ +/* Defines for Video Output Port Register at address 0x191 */ + +/* Bit 0: VIP code T bit polarity */ + +#define VP_T_CODE_P_NON_INVERTED 0x00 +#define VP_T_CODE_P_INVERTED 0x01 + +/* ------------------------------------------------------------------ */ +/* Defines for Video Output Port Register at address 0x195 */ + +/* Bit 2: Video output clock delay control */ + +#define VP_CLK_CTRL2_NOT_DELAYED 0x00 +#define VP_CLK_CTRL2_DELAYED 0x04 + +/* Bit 1: Video output clock invert control */ + +#define VP_CLK_CTRL1_NON_INVERTED 0x00 +#define VP_CLK_CTRL1_INVERTED 0x02 + +/* ------------------------------------------------------------------ */ +/* Defines for Video Output Port Register at address 0x196 */ + +/* Bits 2 to 0: VSYNC pin video vertical sync type */ + +#define VP_VS_TYPE_MASK 0x07 + +#define VP_VS_TYPE_OFF 0x00 +#define VP_VS_TYPE_V123 0x01 +#define VP_VS_TYPE_V_ITU 0x02 +#define VP_VS_TYPE_VGATE_L 0x03 +#define VP_VS_TYPE_RESERVED1 0x04 +#define VP_VS_TYPE_RESERVED2 0x05 +#define VP_VS_TYPE_F_ITU 0x06 +#define VP_VS_TYPE_SC_FID 0x07 + +/* ------------------------------------------------------------------ */ /* data structs for video */ static int video_out[][9] = { @@ -273,12 +313,12 @@ static struct saa7134_tvnorm tvnorms[] = { .h_start = 0, .h_stop = 719, - .video_v_start = 23, - .video_v_stop = 262, - .vbi_v_start_0 = 10, - .vbi_v_stop_0 = 21, - .vbi_v_start_1 = 273, - .src_timing = 7, + .video_v_start = 23, + .video_v_stop = 262, + .vbi_v_start_0 = 10, + .vbi_v_stop_0 = 21, + .vbi_v_start_1 = 273, + .src_timing = 7, .sync_control = 0x18, .luma_control = 0x40, @@ -622,7 +662,7 @@ static void set_size(struct saa7134_dev *dev, int task, prescale = 1; xscale = 1024 * dev->crop_current.width / prescale / width; yscale = 512 * div * dev->crop_current.height / height; - dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); + dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); set_h_prescale(dev,task,prescale); saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); @@ -752,20 +792,20 @@ static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win) maxh = dev->crop_current.height; if (V4L2_FIELD_ANY == field) { - field = (win->w.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } + field = (win->w.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_TOP; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } win->field = field; if (win->w.width > maxw) @@ -1306,13 +1346,13 @@ video_poll(struct file *file, struct poll_table_struct *wait) if (res_locked(fh->dev,RESOURCE_VIDEO)) { up(&fh->cap.lock); return POLLERR; - } - if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) { - up(&fh->cap.lock); - return POLLERR; - } - fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); - fh->cap.read_off = 0; + } + if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) { + up(&fh->cap.lock); + return POLLERR; + } + fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); + fh->cap.read_off = 0; } up(&fh->cap.lock); buf = fh->cap.read_buf; @@ -1666,9 +1706,10 @@ static int video_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; + unsigned int tuner_type = dev->tuner_type; memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); + strcpy(cap->driver, "saa7134"); strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); @@ -1677,9 +1718,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file, V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_TUNER | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + V4L2_CAP_STREAMING | + V4L2_CAP_TUNER; + + if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) + cap->capabilities &= ~V4L2_CAP_TUNER; + return 0; } @@ -1793,9 +1838,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file, crop->c.height = b->top - crop->c.top + b->height; if (crop->c.left < b->left) - crop->c.top = b->left; + crop->c.left = b->left; if (crop->c.left > b->left + b->width) - crop->c.top = b->left + b->width; + crop->c.left = b->left + b->width; if (crop->c.width > b->left - crop->c.left + b->width) crop->c.width = b->left - crop->c.left + b->width; @@ -1817,6 +1862,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, break; if (NULL != card_in(dev,n).name) { strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | @@ -1892,26 +1938,26 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_S_AUDIO: return 0; - case VIDIOC_G_PARM: - { - struct v4l2_captureparm *parm = arg; - memset(parm,0,sizeof(*parm)); - return 0; - } - - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; - - *p = v4l2_prio_max(&dev->prio); - return 0; - } - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; - - return v4l2_prio_change(&dev->prio, &fh->prio, *prio); - } + case VIDIOC_G_PARM: + { + struct v4l2_captureparm *parm = arg; + memset(parm,0,sizeof(*parm)); + return 0; + } + + case VIDIOC_G_PRIORITY: + { + enum v4l2_priority *p = arg; + + *p = v4l2_prio_max(&dev->prio); + return 0; + } + case VIDIOC_S_PRIORITY: + { + enum v4l2_priority *prio = arg; + + return v4l2_prio_change(&dev->prio, &fh->prio, *prio); + } /* --- preview ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: @@ -2018,7 +2064,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_format *f = arg; return saa7134_try_fmt(dev,fh,f); } - +#ifdef HAVE_V4L1 case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; @@ -2043,6 +2089,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } return 0; } +#endif case VIDIOC_REQBUFS: return videobuf_reqbufs(saa7134_queue(fh),arg); @@ -2060,7 +2107,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, { int res = saa7134_resource(fh); - if (!res_get(dev,fh,res)) + if (!res_get(dev,fh,res)) return -EBUSY; return videobuf_streamon(saa7134_queue(fh)); } @@ -2102,7 +2149,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); + strcpy(cap->driver, "saa7134"); strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); @@ -2119,6 +2166,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, memset(t,0,sizeof(*t)); strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); @@ -2233,7 +2281,7 @@ struct video_device saa7134_video_template = { .name = "saa7134-video", .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY| - VID_TYPE_CLIPPING|VID_TYPE_SCALES, + VID_TYPE_CLIPPING|VID_TYPE_SCALES, .hardware = 0, .fops = &video_fops, .minor = -1, @@ -2280,7 +2328,7 @@ int saa7134_video_init1(struct saa7134_dev *dev) dev->tda9887_conf |= TDA9887_AUTOMUTE; dev->automute = 0; - INIT_LIST_HEAD(&dev->video_q.queue); + INIT_LIST_HEAD(&dev->video_q.queue); init_timer(&dev->video_q.timeout); dev->video_q.timeout.function = saa7134_buffer_timeout; dev->video_q.timeout.data = (unsigned long)(&dev->video_q); @@ -2289,13 +2337,28 @@ int saa7134_video_init1(struct saa7134_dev *dev) if (saa7134_boards[dev->board].video_out) { /* enable video output */ int vo = saa7134_boards[dev->board].video_out; + int video_reg; + unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts; saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]); + video_reg = video_out[vo][1]; + if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED) + video_reg &= ~VP_T_CODE_P_INVERTED; + saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg); saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]); - saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]); + video_reg = video_out[vo][5]; + if (vid_port_opts & SET_CLOCK_NOT_DELAYED) + video_reg &= ~VP_CLK_CTRL2_DELAYED; + if (vid_port_opts & SET_CLOCK_INVERTED) + video_reg |= VP_CLK_CTRL1_INVERTED; + saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg); + video_reg = video_out[vo][6]; + if (vid_port_opts & SET_VSYNC_OFF) { + video_reg &= ~VP_VS_TYPE_MASK; + video_reg |= VP_VS_TYPE_OFF; + } + saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg); saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); } diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 860b89530e2a..fb9727471661 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -24,16 +24,18 @@ #include <linux/pci.h> #include <linux/i2c.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <linux/kdev_t.h> #include <linux/input.h> +#include <linux/notifier.h> +#include <linux/delay.h> #include <asm/io.h> #include <media/tuner.h> #include <media/audiochip.h> -#include <media/id.h> #include <media/ir-common.h> +#include <media/ir-kbd-i2c.h> #include <media/video-buf.h> #include <media/video-buf-dvb.h> @@ -45,6 +47,10 @@ #endif #define UNSET (-1U) +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/pcm.h> + /* ----------------------------------------------------------- */ /* enums */ @@ -187,10 +193,39 @@ struct saa7134_format { #define SAA7134_BOARD_FLYTV_DIGIMATRIX 64 #define SAA7134_BOARD_KWORLD_TERMINATOR 65 #define SAA7134_BOARD_YUAN_TUN900 66 +#define SAA7134_BOARD_BEHOLD_409FM 67 +#define SAA7134_BOARD_GOTVIEW_7135 68 +#define SAA7134_BOARD_PHILIPS_EUROPA 69 +#define SAA7134_BOARD_VIDEOMATE_DVBT_300 70 +#define SAA7134_BOARD_VIDEOMATE_DVBT_200 71 +#define SAA7134_BOARD_RTD_VFG7350 72 +#define SAA7134_BOARD_RTD_VFG7330 73 +#define SAA7134_BOARD_FLYTVPLATINUM_MINI2 74 +#define SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180 75 +#define SAA7134_BOARD_MONSTERTV_MOBILE 76 +#define SAA7134_BOARD_PINNACLE_PCTV_110i 77 +#define SAA7134_BOARD_ASUSTeK_P7131_DUAL 78 +#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS 79 +#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80 +#define SAA7134_BOARD_PHILIPS_TIGER 81 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 +/* ----------------------------------------------------------- */ +/* Since we support 2 remote types, lets tell them apart */ + +#define SAA7134_REMOTE_GPIO 1 +#define SAA7134_REMOTE_I2C 2 + +/* ----------------------------------------------------------- */ +/* Video Output Port Register Initialization Options */ + +#define SET_T_CODE_POLARITY_NON_INVERTED (1 << 0) +#define SET_CLOCK_NOT_DELAYED (1 << 1) +#define SET_CLOCK_INVERTED (1 << 2) +#define SET_VSYNC_OFF (1 << 3) + struct saa7134_input { char *name; unsigned int vmux; @@ -226,6 +261,7 @@ struct saa7134_board { /* peripheral I/O */ enum saa7134_video_out video_out; enum saa7134_mpeg_type mpeg; + unsigned int vid_port_opts; }; #define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name) @@ -319,9 +355,9 @@ struct saa7134_fh { struct saa7134_pgtable pt_vbi; }; -/* oss dsp status */ -struct saa7134_oss { - struct semaphore lock; +/* dmasound dsp status */ +struct saa7134_dmasound { + struct semaphore lock; int minor_mixer; int minor_dsp; unsigned int users_dsp; @@ -347,6 +383,7 @@ struct saa7134_oss { unsigned int dma_blk; unsigned int read_offset; unsigned int read_count; + snd_pcm_substream_t *substream; }; /* IR input */ @@ -358,9 +395,9 @@ struct saa7134_ir { u32 mask_keycode; u32 mask_keydown; u32 mask_keyup; - int polling; - u32 last_gpio; - struct timer_list timer; + int polling; + u32 last_gpio; + struct timer_list timer; }; /* ts/mpeg status */ @@ -383,8 +420,8 @@ struct saa7134_mpeg_ops { /* global device status */ struct saa7134_dev { struct list_head devlist; - struct semaphore lock; - spinlock_t slock; + struct semaphore lock; + spinlock_t slock; #ifdef VIDIOC_G_PRIORITY struct v4l2_prio_state prio; #endif @@ -394,7 +431,7 @@ struct saa7134_dev { struct video_device *video_dev; struct video_device *radio_dev; struct video_device *vbi_dev; - struct saa7134_oss oss; + struct saa7134_dmasound dmasound; /* infrared remote */ int has_remote; @@ -421,7 +458,7 @@ struct saa7134_dev { /* i2c i/o */ struct i2c_adapter i2c_adap; struct i2c_client i2c_client; - unsigned char eedata[64]; + unsigned char eedata[128]; /* video overlay */ struct v4l2_framebuffer ovbuf; @@ -626,6 +663,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status); int saa7134_input_init1(struct saa7134_dev *dev); void saa7134_input_fini(struct saa7134_dev *dev); void saa7134_input_irq(struct saa7134_dev *dev); +void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir); /* * Local variables: |