]> git.hungrycats.org Git - linux/commitdiff
[PATCH] v4l: saa7134 cleanups and new cards.
authorAndrew Morton <akpm@osdl.org>
Fri, 6 Feb 2004 00:52:13 +0000 (16:52 -0800)
committerGreg Kroah-Hartman <greg@kroah.com>
Fri, 6 Feb 2004 00:52:13 +0000 (16:52 -0800)
From: Gerd Knorr <kraxel@bytesex.org>

This patch is a update for the saa7134 driver in the linux kernel.

Changes:

* kernel thread cleanups (exit/rmmod sync using completions, wait queue
  fixes).

* add support for more cards.

* improved infrared remote support.

drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134.h

index 7bb35655de42445f024514d1fc71b77fa1120a94..f60777a6ed75cd59af0b9c885c7c1a896c23dc66 100644 (file)
@@ -834,7 +834,7 @@ struct saa7134_board saa7134_boards[] = {
                }},
        },
         [SAA7134_BOARD_ECS_TVP3XP] = {
-                .name           = "Elitegroup ECS TVP3XP FM1216 Tuner Card",
+                .name           = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ",
                 .audio_clock    = 0x187de7,  // xtal 32.1 MHz
                 .tuner_type     = TUNER_PHILIPS_PAL,
                 .inputs         = {{
@@ -865,6 +865,82 @@ struct saa7134_board saa7134_boards[] = {
                         .amux   = LINE2,
                 },
         },
+        [SAA7134_BOARD_ECS_TVP3XP_4CB5] = {
+                .name           = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)",
+                .audio_clock    = 0x187de7,
+                .tuner_type     = TUNER_PHILIPS_NTSC,
+                .inputs         = {{
+                        .name   = name_tv,
+                        .vmux   = 1,
+                        .amux   = TV,
+                        .tv     = 1,
+                },{
+                        .name   = name_tv_mono,
+                        .vmux   = 1,
+                        .amux   = LINE2,
+                        .tv     = 1,
+                },{
+                        .name   = name_comp1,
+                        .vmux   = 3,
+                        .amux   = LINE1,
+                },{
+                        .name   = name_svideo,
+                        .vmux   = 8,
+                        .amux   = LINE1,
+                },{
+                        .name   = "CVid over SVid",
+                        .vmux   = 0,
+                        .amux   = LINE1,
+                }},
+                .radio = {
+                        .name   = name_radio,
+                        .amux   = LINE2,
+                },
+        },
+       [SAA7134_BOARD_AVACSSMARTTV] = {
+               /* Roman Pszonczenko <romka@kolos.math.uni.lodz.pl> */
+               .name           = "AVACS SmartTV",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_PAL,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+                },{
+                       .name = name_tv_mono,
+                       .vmux = 1,
+                       .amux = LINE2,
+                       .tv   = 1,
+               },{
+                       .name = name_comp1,
+                       .vmux = 0,
+                       .amux = LINE2,
+               },{
+                       .name = name_comp2,
+                       .vmux = 3,
+                       .amux = LINE2,
+               },{
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE2,
+               }},
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0x200000,
+               },
+       },
+       [SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER] = {
+               /* Michael Smith <msmith@cbnco.com> */
+               .name           = "AVerMedia DVD EZMaker",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_ABSENT,
+               .inputs         = {{
+                       .name = name_comp1,
+                       .vmux = 3,
+               }},
+       },
 };
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
 
@@ -1023,6 +1099,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                 .subvendor    = 0x1461, /* Avermedia Technologies Inc */
                 .subdevice    = 0x2115,
                .driver_data  = SAA7134_BOARD_MD2819,
+       },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+                .subdevice    = 0x10ff,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER,
         },{
                /* TransGear 3000TV */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -1043,6 +1125,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                 .subdevice    = 0x4cb4,
                 .driver_data  = SAA7134_BOARD_ECS_TVP3XP,
         },{
+                .vendor       = PCI_VENDOR_ID_PHILIPS,
+                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .subvendor    = 0x1019,
+                .subdevice    = 0x4cb5,
+                .driver_data  = SAA7134_BOARD_ECS_TVP3XP_4CB5,
+        },{
                
                /* --- boards without eeprom + subsystem ID --- */
                 .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -1149,6 +1237,8 @@ int saa7134_board_init(struct saa7134_dev *dev)
                break;
        case SAA7134_BOARD_CINERGY400:
        case SAA7134_BOARD_CINERGY600:
+       case SAA7134_BOARD_ECS_TVP3XP:
+       case SAA7134_BOARD_ECS_TVP3XP_4CB5:
                dev->has_remote = 1;
                break;
        }
index 9a39e8c3178b1c79c40c326d05eb56ff6b749fc2..9dfb4848863acefcc7760201aa275d90c2be7da8 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * handle saa7134 IR remotes via linux kernel input layer.
+ *
  * 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; either version 2 of the License, or
@@ -13,9 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/module.h>
@@ -101,6 +100,63 @@ static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
        [ 0x23 ] = KEY_STOP,
 };
 
+/* Alfons Geser <a.geser@cox.net> */
+static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
+        [ 18 ] = KEY_POWER,
+        [  1 ] = KEY_TV,             // DVR
+        [ 21 ] = KEY_VIDEO,          // DVD
+        [ 23 ] = KEY_AUDIO,          // music
+
+                                     // DVR mode / DVD mode / music mode
+
+        [ 27 ] = KEY_MUTE,           // mute
+        [  2 ] = KEY_RESERVED,       // MTS/SAP / audio /autoseek
+        [ 30 ] = KEY_RESERVED,       // closed captioning / subtitle / seek
+        [ 22 ] = KEY_ZOOM,           // full screen
+        [ 28 ] = KEY_RESERVED,       // video source / eject /delall
+        [ 29 ] = KEY_RESERVED,       // playback / angle /del
+        [ 47 ] = KEY_SEARCH,         // scan / menu / playlist
+        [ 48 ] = KEY_RESERVED,       // CH surfing / bookmark / memo
+
+        [ 49 ] = KEY_HELP,           // help
+        [ 50 ] = KEY_RESERVED,       // num/memo
+        [ 51 ] = KEY_ESC,            // cancel
+
+       [ 12 ] = KEY_UP,             // up
+       [ 16 ] = KEY_DOWN,           // down
+       [  8 ] = KEY_LEFT,           // left
+       [  4 ] = KEY_RIGHT,          // right
+       [  3 ] = KEY_ENTER,          // select
+
+       [ 31 ] = KEY_REWIND,         // rewind
+       [ 32 ] = KEY_PLAYPAUSE,      // play/pause
+       [ 41 ] = KEY_FORWARD,        // forward
+       [ 20 ] = KEY_RESERVED,       // repeat
+       [ 43 ] = KEY_RECORD,         // recording
+       [ 44 ] = KEY_STOP,           // stop
+       [ 45 ] = KEY_PLAY,           // play
+       [ 46 ] = KEY_RESERVED,       // snapshot
+
+        [  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 int build_key(struct saa7134_dev *dev)
@@ -111,9 +167,15 @@ static int build_key(struct saa7134_dev *dev)
        /* rising SAA7134_GPIO_GPRESCAN reads the status */
        saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
        saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
+
        gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
-       data = ir_extract_bits(gpio, ir->mask_keycode);
+        if (ir->polling) {
+                if (ir->last_gpio == gpio)
+                        return 0;
+                ir->last_gpio = gpio;
+        }
 
+       data = ir_extract_bits(gpio, ir->mask_keycode);
        printk("%s: build_key gpio=0x%x mask=0x%x data=%d\n",
               dev->name, gpio, ir->mask_keycode, data);
 
@@ -130,7 +192,21 @@ static int build_key(struct saa7134_dev *dev)
 
 void saa7134_input_irq(struct saa7134_dev *dev)
 {
+        struct saa7134_ir *ir = dev->remote;
+
+        if (!ir->polling)
+               build_key(dev);
+}
+
+static void saa7134_input_timer(unsigned long data)
+{
+       struct saa7134_dev *dev = (struct saa7134_dev*)data;
+       struct saa7134_ir *ir = dev->remote;
+       unsigned long timeout;
+
        build_key(dev);
+       timeout = jiffies + (ir->polling * HZ / 1000);
+       mod_timer(&ir->timer, timeout);
 }
 
 int saa7134_input_init1(struct saa7134_dev *dev)
@@ -140,6 +216,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        u32 mask_keycode = 0;
        u32 mask_keydown = 0;
        u32 mask_keyup   = 0;
+       int polling      = 0;
        int ir_type      = IR_TYPE_OTHER;
 
        /* detect & configure */
@@ -158,6 +235,13 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keycode = 0x00003f;
                mask_keyup   = 0x040000;
                break;
+       case SAA7134_BOARD_ECS_TVP3XP:
+       case SAA7134_BOARD_ECS_TVP3XP_4CB5:
+                ir_codes     = eztv_codes;
+                mask_keycode = 0x00017c;
+                mask_keyup   = 0x000002;
+               polling      = 50; // ms
+                break;
        }
        if (NULL == ir_codes) {
                printk("%s: Oops: IR config error [card=%d]\n",
@@ -174,6 +258,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;
        
        /* init input device */
        snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -196,6 +281,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 
        /* all done */
        dev->remote = ir;
+       if (ir->polling) {
+               init_timer(&ir->timer);
+               ir->timer.function = saa7134_input_timer;
+               ir->timer.data     = (unsigned long)dev;
+               ir->timer.expires  = jiffies + HZ;
+               add_timer(&ir->timer);
+       }
+
        input_register_device(&dev->remote->dev);
        printk("%s: registered input device for IR\n",dev->name);
        return 0;
@@ -207,6 +300,8 @@ void saa7134_input_fini(struct saa7134_dev *dev)
                return;
        
        input_unregister_device(&dev->remote->dev);
+       if (dev->remote->polling)
+               del_timer_sync(&dev->remote->timer);
        kfree(dev->remote);
        dev->remote = NULL;
 }
index 983497ad15f98492704a9f9c8e8bae164f2f519d..907b865a5f7d33aa9216305b227139ac497ecacd 100644 (file)
@@ -45,6 +45,9 @@ static unsigned int audio_ddep = 0;
 MODULE_PARM(audio_ddep,"i");
 MODULE_PARM_DESC(audio_ddep,"audio ddep overwrite");
 
+static int audio_clock_override = UNSET;
+MODULE_PARM(audio_clock_override, "i");
+
 static int audio_clock_tweak = 0;
 MODULE_PARM(audio_clock_tweak, "i");
 MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])");
@@ -140,6 +143,9 @@ static void tvaudio_init(struct saa7134_dev *dev)
 {
        int clock = saa7134_boards[dev->board].audio_clock;
 
+       if (UNSET != audio_clock_override)
+               clock = audio_clock_override;
+
        /* init all audio registers */
        saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
        if (need_resched())
@@ -296,8 +302,13 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
        DECLARE_WAITQUEUE(wait, current);
        
        add_wait_queue(&dev->thread.wq, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-       schedule_timeout(timeout);
+       if (dev->thread.scan1 == dev->thread.scan2 && !dev->thread.shutdown) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (timeout < 0)
+                       schedule();
+               else
+                       schedule_timeout(timeout);
+       }
        remove_wait_queue(&dev->thread.wq, &wait);
        return dev->thread.scan1 != dev->thread.scan2;
 }
@@ -457,18 +468,11 @@ static int tvaudio_thread(void *data)
        unsigned int i, audio;
        int max1,max2,carrier,rx,mode,lastmode;
 
-       lock_kernel();
        daemonize("%s", dev->name);
-       dev->thread.task = current;
-       unlock_kernel();
-       if (dev->thread.notify != NULL)
-               up(dev->thread.notify);
-
+       allow_signal(SIGTERM);
        for (;;) {
-               if (dev->thread.exit || signal_pending(current))
-                       goto done;
-               interruptible_sleep_on(&dev->thread.wq);
-               if (dev->thread.exit || signal_pending(current))
+               tvaudio_sleep(dev,-1);
+               if (dev->thread.shutdown || signal_pending(current))
                        goto done;
 
        restart:
@@ -571,7 +575,7 @@ static int tvaudio_thread(void *data)
                for (;;) {
                        if (tvaudio_sleep(dev,5*HZ))
                                goto restart;
-                       if (dev->thread.exit || signal_pending(current))
+                       if (dev->thread.shutdown || signal_pending(current))
                                break;
                        if (UNSET == dev->thread.mode) {
                                rx = tvaudio_getstereo(dev,&tvaudio[i]);
@@ -587,9 +591,7 @@ static int tvaudio_thread(void *data)
        }
 
  done:
-       dev->thread.task = NULL;
-       if(dev->thread.notify != NULL)
-               up(dev->thread.notify);
+       complete_and_exit(&dev->thread.exit, 0);
        return 0;
 }
 
@@ -721,22 +723,16 @@ static int tvaudio_thread_ddep(void *data)
        struct saa7134_dev *dev = data;
        u32 value, norms;
 
-       lock_kernel();
        daemonize("%s", dev->name);
-       dev->thread.task = current;
-       unlock_kernel();
-       if (dev->thread.notify != NULL)
-               up(dev->thread.notify);
+       allow_signal(SIGTERM);
 
        /* unmute */
        saa_dsp_writel(dev, 0x474 >> 2, 0x00);
        saa_dsp_writel(dev, 0x450 >> 2, 0x00);
 
        for (;;) {
-               if (dev->thread.exit || signal_pending(current))
-                       goto done;
-               interruptible_sleep_on(&dev->thread.wq);
-               if (dev->thread.exit || signal_pending(current))
+               tvaudio_sleep(dev,-1);
+               if (dev->thread.shutdown || signal_pending(current))
                        goto done;
 
        restart:
@@ -808,9 +804,7 @@ static int tvaudio_thread_ddep(void *data)
        }
 
  done:
-       dev->thread.task = NULL;
-       if(dev->thread.notify != NULL)
-               up(dev->thread.notify);
+       complete_and_exit(&dev->thread.exit, 0);
        return 0;
 }
 
@@ -893,7 +887,6 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 {
        DECLARE_MUTEX_LOCKED(sem);
        int (*my_thread)(void *data) = NULL;
-       int rc;
 
        /* enable I2S audio output */
        if (saa7134_boards[dev->board].i2s_rate) {
@@ -915,17 +908,16 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
                my_thread = tvaudio_thread_ddep;
                break;
        }
+
+       dev->thread.pid = -1;
        if (my_thread) {
                /* start tvaudio thread */
                init_waitqueue_head(&dev->thread.wq);
-               dev->thread.notify = &sem;
-               rc = kernel_thread(my_thread,dev,0);
-               if (rc < 0)
+               init_completion(&dev->thread.exit);
+               dev->thread.pid = kernel_thread(my_thread,dev,0);
+               if (dev->thread.pid < 0)
                        printk(KERN_WARNING "%s: kernel_thread() failed\n",
                               dev->name);
-               else
-                       down(&sem);
-               dev->thread.notify = NULL;
                wake_up_interruptible(&dev->thread.wq);
        }
 
@@ -934,15 +926,11 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 
 int saa7134_tvaudio_fini(struct saa7134_dev *dev)
 {
-       DECLARE_MUTEX_LOCKED(sem);
-
        /* shutdown tvaudio thread */
-       if (dev->thread.task) {
-               dev->thread.notify = &sem;
-               dev->thread.exit = 1;
+       if (dev->thread.pid >= 0) {
+               dev->thread.shutdown = 1;
                wake_up_interruptible(&dev->thread.wq);
-               down(&sem);
-               dev->thread.notify = NULL;
+               wait_for_completion(&dev->thread.exit);
        }
        saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
        return 0;
@@ -950,7 +938,7 @@ int saa7134_tvaudio_fini(struct saa7134_dev *dev)
 
 int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
 {
-       if (dev->thread.task) {
+       if (dev->thread.pid >= 0) {
                dev->thread.mode = UNSET;
                dev->thread.scan2++;
                wake_up_interruptible(&dev->thread.wq);
index 9ba0cf919ff6e8492a8c4a9e42b21dfba646d38f..9c14b7e612a5ad0ee258c4bdc0aed14ab5536c17 100644 (file)
@@ -151,6 +151,9 @@ struct saa7134_format {
 #define SAA7134_BOARD_MANLI_MTV001     28
 #define SAA7134_BOARD_TG3000TV         29
 #define SAA7134_BOARD_ECS_TVP3XP       30
+#define SAA7134_BOARD_ECS_TVP3XP_4CB5  31
+#define SAA7134_BOARD_AVACSSMARTTV     32
+#define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33
 
 #define SAA7134_INPUT_MAX 8
 
@@ -212,10 +215,10 @@ struct saa7134_pgtable {
 
 /* tvaudio thread status */
 struct saa7134_thread {
-       struct task_struct         *task;
+       pid_t                      pid;
+       struct completion          exit;
        wait_queue_head_t          wq;
-       struct semaphore           *notify;
-       unsigned int               exit;
+       unsigned int               shutdown;
        unsigned int               scan1;
        unsigned int               scan2;
        unsigned int               mode;
@@ -319,6 +322,9 @@ struct saa7134_ir {
        u32                        mask_keycode;
        u32                        mask_keydown;
        u32                        mask_keyup;
+        int                        polling;
+        u32                        last_gpio;
+        struct timer_list          timer;
 };
 
 /* global device status */