Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[pandora-kernel.git] / drivers / media / dvb / dvb-core / dvb_ca_en50221.c
index 00347a7..8e5dd7b 100644 (file)
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/sched.h>
+#include <linux/kthread.h>
 
 #include "dvb_ca_en50221.h"
 #include "dvb_ringbuffer.h"
@@ -140,13 +140,7 @@ struct dvb_ca_private {
        wait_queue_head_t wait_queue;
 
        /* PID of the monitoring thread */
-       pid_t thread_pid;
-
-       /* Wait queue used when shutting thread down */
-       wait_queue_head_t thread_queue;
-
-       /* Flag indicating when thread should exit */
-       unsigned int exit:1;
+       struct task_struct *thread;
 
        /* Flag indicating if the CA device is open */
        unsigned int open:1;
@@ -175,7 +169,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * e
  * @param nlen Number of bytes in needle.
  * @return Pointer into haystack needle was found at, or NULL if not found.
  */
-static u8 *findstr(u8 * haystack, int hlen, u8 * needle, int nlen)
+static char *findstr(char * haystack, int hlen, char * needle, int nlen)
 {
        int i;
 
@@ -256,7 +250,7 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
        unsigned long timeout;
        unsigned long start;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        /* loop until timeout elapsed */
        start = jiffies;
@@ -269,7 +263,7 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
 
                /* if we got the flags, it was successful! */
                if (res & waitfor) {
-                       dprintk("%s succeeded timeout:%lu\n", __FUNCTION__, jiffies - start);
+                       dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start);
                        return 0;
                }
 
@@ -282,7 +276,7 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
                msleep(1);
        }
 
-       dprintk("%s failed timeout:%lu\n", __FUNCTION__, jiffies - start);
+       dprintk("%s failed timeout:%lu\n", __func__, jiffies - start);
 
        /* if we get here, we've timed out */
        return -ETIMEDOUT;
@@ -303,7 +297,7 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
        int buf_size;
        u8 buf[2];
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        /* we'll be determining these during this function */
        ca->slot_info[slot].da_irq_supported = 0;
@@ -482,7 +476,7 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
        }
 
        /* check it contains the correct DVB string */
-       dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
+       dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
        if (dvb_str == NULL)
                return -EINVAL;
        if (tupleLength < ((dvb_str - (char *) tuple) + 12))
@@ -513,8 +507,8 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
                        ca->slot_info[slot].config_option = tuple[0] & 0x3f;
 
                        /* OK, check it contains the correct strings */
-                       if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
-                           (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
+                       if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+                           (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
                                break;
 
                        got_cftableentry = 1;
@@ -555,7 +549,7 @@ static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
 {
        int configoption;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        /* set the config option */
        ca->pub->write_attribute_mem(ca->pub, slot,
@@ -593,7 +587,7 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * eb
        u8 buf[HOST_LINK_BUF_SIZE];
        int i;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        /* check if we have space for a link buf in the rx_buffer */
        if (ebuf == NULL) {
@@ -714,7 +708,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * b
        int status;
        int i;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
 
        // sanity check
@@ -791,7 +785,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
  */
 static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
 {
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        ca->pub->slot_shutdown(ca->pub, slot);
        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
@@ -898,31 +892,13 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
 static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
 {
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        ca->wakeup = 1;
        mb();
-       wake_up_interruptible(&ca->thread_queue);
+       wake_up_process(ca->thread);
 }
 
-/**
- * Used by the CA thread to determine if an early wakeup is necessary
- *
- * @param ca CA instance.
- */
-static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca)
-{
-       if (ca->wakeup) {
-               ca->wakeup = 0;
-               return 1;
-       }
-       if (ca->exit)
-               return 1;
-
-       return 0;
-}
-
-
 /**
  * Update the delay used by the thread.
  *
@@ -934,15 +910,21 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
        int curdelay = 100000000;
        int slot;
 
+       /* Beware of too high polling frequency, because one polling
+        * call might take several hundred milliseconds until timeout!
+        */
        for (slot = 0; slot < ca->slot_count; slot++) {
                switch (ca->slot_info[slot].slot_state) {
                default:
                case DVB_CA_SLOTSTATE_NONE:
+                       delay = HZ * 60;  /* 60s */
+                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+                               delay = HZ * 5;  /* 5s */
+                       break;
                case DVB_CA_SLOTSTATE_INVALID:
-                       delay = HZ * 60;
-                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
-                               delay = HZ / 10;
-                       }
+                       delay = HZ * 60;  /* 60s */
+                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+                               delay = HZ / 10;  /* 100ms */
                        break;
 
                case DVB_CA_SLOTSTATE_UNINITIALISED:
@@ -950,19 +932,17 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
                case DVB_CA_SLOTSTATE_VALIDATE:
                case DVB_CA_SLOTSTATE_WAITFR:
                case DVB_CA_SLOTSTATE_LINKINIT:
-                       delay = HZ / 10;
+                       delay = HZ / 10;  /* 100ms */
                        break;
 
                case DVB_CA_SLOTSTATE_RUNNING:
-                       delay = HZ * 60;
-                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
-                               delay = HZ / 10;
-                       }
+                       delay = HZ * 60;  /* 60s */
+                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+                               delay = HZ / 10;  /* 100ms */
                        if (ca->open) {
                                if ((!ca->slot_info[slot].da_irq_supported) ||
-                                   (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) {
-                                       delay = HZ / 10;
-                               }
+                                   (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA)))
+                                       delay = HZ / 10;  /* 100ms */
                        }
                        break;
                }
@@ -982,37 +962,25 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
 static int dvb_ca_en50221_thread(void *data)
 {
        struct dvb_ca_private *ca = data;
-       char name[15];
        int slot;
        int flags;
        int status;
        int pktcount;
        void *rxbuf;
 
-       dprintk("%s\n", __FUNCTION__);
-
-       /* setup kernel thread */
-       snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id);
-
-       lock_kernel();
-       daemonize(name);
-       sigfillset(&current->blocked);
-       unlock_kernel();
+       dprintk("%s\n", __func__);
 
        /* choose the correct initial delay */
        dvb_ca_en50221_thread_update_delay(ca);
 
        /* main loop */
-       while (!ca->exit) {
+       while (!kthread_should_stop()) {
                /* sleep for a bit */
                if (!ca->wakeup) {
-                       flags = wait_event_interruptible_timeout(ca->thread_queue,
-                                                                dvb_ca_en50221_thread_should_wakeup(ca),
-                                                                ca->delay);
-                       if ((flags == -ERESTARTSYS) || ca->exit) {
-                               /* got signal or quitting */
-                               break;
-                       }
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(ca->delay);
+                       if (kthread_should_stop())
+                               return 0;
                }
                ca->wakeup = 0;
 
@@ -1060,8 +1028,18 @@ static int dvb_ca_en50221_thread(void *data)
                                break;
 
                        case DVB_CA_SLOTSTATE_VALIDATE:
-                               if (dvb_ca_en50221_parse_attributes(ca, slot)
-                                   != 0) {
+                               if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+                                       /* we need this extra check for annoying interfaces like the budget-av */
+                                       if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+                                           (ca->pub->poll_slot_status)) {
+                                               int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+                                               if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+                                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+                                                       dvb_ca_en50221_thread_update_delay(ca);
+                                                       break;
+                                               }
+                                       }
+
                                        printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
                                               ca->dvbdev->adapter->num);
                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
@@ -1108,6 +1086,17 @@ static int dvb_ca_en50221_thread(void *data)
 
                        case DVB_CA_SLOTSTATE_LINKINIT:
                                if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+                                       /* we need this extra check for annoying interfaces like the budget-av */
+                                       if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+                                           (ca->pub->poll_slot_status)) {
+                                               int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+                                               if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+                                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+                                                       dvb_ca_en50221_thread_update_delay(ca);
+                                                       break;
+                                               }
+                                       }
+
                                        printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
                                        dvb_ca_en50221_thread_update_delay(ca);
@@ -1160,10 +1149,6 @@ static int dvb_ca_en50221_thread(void *data)
                }
        }
 
-       /* completed */
-       ca->thread_pid = 0;
-       mb();
-       wake_up_interruptible(&ca->thread_queue);
        return 0;
 }
 
@@ -1191,7 +1176,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file,
        int err = 0;
        int slot;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        switch (cmd) {
        case CA_RESET:
@@ -1279,13 +1264,13 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
        struct dvb_ca_private *ca = dvbdev->priv;
        u8 slot, connection_id;
        int status;
-       char fragbuf[HOST_LINK_BUF_SIZE];
+       u8 fragbuf[HOST_LINK_BUF_SIZE];
        int fragpos = 0;
        int fraglen;
        unsigned long timeout;
        int written;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
        if (count < 2)
@@ -1372,7 +1357,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
 
                idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
                while (idx != -1) {
-                       dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+                       dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
                        if (connection_id == -1)
                                connection_id = hdr[0];
                        if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
@@ -1420,7 +1405,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
        int pktlen;
        int dispose = 0;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
        if (count < 2)
@@ -1453,7 +1438,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
                        goto exit;
                }
 
-               dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+               dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
                if (connection_id == -1)
                        connection_id = hdr[0];
                if (hdr[0] == connection_id) {
@@ -1464,8 +1449,8 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
                                        fraglen -= 2;
                                }
 
-                               if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
-                                                                     buf + pktlen, fraglen, 1)) < 0) {
+                               if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2,
+                                                                     buf + pktlen, fraglen)) < 0) {
                                        goto exit;
                                }
                                pktlen += fraglen;
@@ -1509,14 +1494,16 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
        int err;
        int i;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        if (!try_module_get(ca->pub->owner))
                return -EIO;
 
        err = dvb_generic_open(inode, file);
-       if (err < 0)
+       if (err < 0) {
+               module_put(ca->pub->owner);
                return err;
+       }
 
        for (i = 0; i < ca->slot_count; i++) {
 
@@ -1549,9 +1536,9 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dvb_ca_private *ca = dvbdev->priv;
-       int err = 0;
+       int err;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        /* mark the CA device as closed */
        ca->open = 0;
@@ -1561,7 +1548,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
 
        module_put(ca->pub->owner);
 
-       return 0;
+       return err;
 }
 
 
@@ -1581,7 +1568,7 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait)
        int slot;
        int result = 0;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
                mask |= POLLIN;
@@ -1643,7 +1630,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
        struct dvb_ca_private *ca = NULL;
        int i;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        if (slot_count < 1)
                return -EINVAL;
@@ -1661,9 +1648,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
                goto error;
        }
        init_waitqueue_head(&ca->wait_queue);
-       ca->thread_pid = 0;
-       init_waitqueue_head(&ca->thread_queue);
-       ca->exit = 0;
        ca->open = 0;
        ca->wakeup = 0;
        ca->next_read_slot = 0;
@@ -1689,14 +1673,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
        mb();
 
        /* create a kthread for monitoring this CA device */
-
-       ret = kernel_thread(dvb_ca_en50221_thread, ca, 0);
-
-       if (ret < 0) {
-               printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret);
+       ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
+                                ca->dvbdev->adapter->num, ca->dvbdev->id);
+       if (IS_ERR(ca->thread)) {
+               ret = PTR_ERR(ca->thread);
+               printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
+                       ret);
                goto error;
        }
-       ca->thread_pid = ret;
        return 0;
 
 error:
@@ -1724,20 +1708,10 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
        struct dvb_ca_private *ca = pubca->private;
        int i;
 
-       dprintk("%s\n", __FUNCTION__);
+       dprintk("%s\n", __func__);
 
        /* shutdown the thread if there was one */
-       if (ca->thread_pid) {
-               if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) {
-                       printk("dvb_ca_release adapter %d: thread PID %d already died\n",
-                              ca->dvbdev->adapter->num, ca->thread_pid);
-               } else {
-                       ca->exit = 1;
-                       mb();
-                       dvb_ca_en50221_thread_wakeup(ca);
-                       wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0);
-               }
-       }
+       kthread_stop(ca->thread);
 
        for (i = 0; i < ca->slot_count; i++) {
                dvb_ca_en50221_slot_shutdown(ca, i);