dvb_ca_en50221.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,628 行 · 第 1/4 页

C
1,628
字号
        case DVB_CA_SLOTSTATE_LINKINIT:                flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);                if (flags & STATUSREG_DA) {                        dprintk("CAM supports DA IRQ\n");                        ca->slot_info[slot].da_irq_supported = 1;		}                break;        case DVB_CA_SLOTSTATE_RUNNING:                flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);                if (flags & STATUSREG_DA) {                        dvb_ca_en50221_thread_wakeup(ca);                }                break;        }}/* ******************************************************************************** *//* EN50221 thread functions *//** * Wake up the DVB CA thread * * @param ca CA instance. */static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private* ca){        dprintk ("%s\n", __FUNCTION__);        ca->wakeup = 1;        mb();        wake_up_interruptible(&ca->thread_queue);}/** * 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. * * @param ca CA instance. */static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private* ca){        int delay;        int curdelay = 100000000;        int slot;        for(slot=0; slot < ca->slot_count; slot++) {                switch(ca->slot_info[slot].slot_state) {                default:                case DVB_CA_SLOTSTATE_NONE:                case DVB_CA_SLOTSTATE_INVALID:                        delay = HZ*60;                        if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {                                delay = HZ/10;                        }                        break;                case DVB_CA_SLOTSTATE_UNINITIALISED:                case DVB_CA_SLOTSTATE_WAITREADY:                case DVB_CA_SLOTSTATE_VALIDATE:                case DVB_CA_SLOTSTATE_WAITFR:                case DVB_CA_SLOTSTATE_LINKINIT:                        delay = HZ/10;                        break;                case DVB_CA_SLOTSTATE_RUNNING:                        delay = HZ*60;                        if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {                                delay = HZ/10;                        }                        if (ca->open) {                                if ((!ca->slot_info[slot].da_irq_supported) ||                                    (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) {                                        delay = HZ/100;                                }                        }                        break;                }                if (delay < curdelay) curdelay = delay;        }        ca->delay = curdelay;}/** * Kernel thread which monitors CA slots for CAM changes, and performs data transfers. */static int dvb_ca_en50221_thread(void* data){        struct dvb_ca_private *ca = (struct dvb_ca_private*) data;        char name[15];        int slot;        int flags;        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);        dvb_kernel_thread_setup(name);        /* choose the correct initial delay */        dvb_ca_en50221_thread_update_delay(ca);        /* main loop */        while(!ca->exit) {                /* 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;                        }                }                ca->wakeup = 0;                /* go through all the slots processing them */                for(slot=0; slot < ca->slot_count; slot++) {                        // check the cam status + deal with CAMCHANGEs                        while(dvb_ca_en50221_check_camstatus(ca, slot)) {                                /* clear down an old CI slot if necessary */                                if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) dvb_ca_en50221_slot_shutdown(ca, slot);                                /* if a CAM is NOW present, initialise it */                                if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;                                }                                /* we've handled one CAMCHANGE */                                dvb_ca_en50221_thread_update_delay(ca);                                atomic_dec(&ca->slot_info[slot].camchange_count);                        }                        // CAM state machine                        switch(ca->slot_info[slot].slot_state) {                        case DVB_CA_SLOTSTATE_NONE:                        case DVB_CA_SLOTSTATE_INVALID:                                // no action needed                                break;                        case DVB_CA_SLOTSTATE_UNINITIALISED:                                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;                                ca->pub->slot_reset(ca->pub, slot);                                ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);                                break;                        case DVB_CA_SLOTSTATE_WAITREADY:                                if (time_after(jiffies, ca->slot_info[slot].timeout)) {                                        printk("dvb_ca: PC card did not respond :(\n");                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;				        dvb_ca_en50221_thread_update_delay(ca);                                        break;                                }                                // no other action needed; will automatically change state when ready                                break;                        case DVB_CA_SLOTSTATE_VALIDATE:                                if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {                                        printk("dvb_ca: Invalid PC card inserted :(\n");                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;				        dvb_ca_en50221_thread_update_delay(ca);                                        break;                                }                                if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {                                        printk("dvb_ca: Unable to initialise CAM :(\n");                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;				        dvb_ca_en50221_thread_update_delay(ca);                                        break;                                }                                dprintk("DVB CAM validated successfully\n");                                ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);                                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;                                ca->wakeup = 1;                                break;                        case DVB_CA_SLOTSTATE_WAITFR:                                if (time_after(jiffies, ca->slot_info[slot].timeout)) {                                        printk("dvb_ca: DVB CAM did not respond :(\n");                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;				        dvb_ca_en50221_thread_update_delay(ca);                                        break;                                }                                flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);                                if (flags & STATUSREG_FR) {                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;                                        ca->wakeup = 1;                                }                                break;                        case DVB_CA_SLOTSTATE_LINKINIT:                                if (dvb_ca_en50221_link_init(ca, slot) != 0) {                                        printk("dvb_ca: DVB CAM link initialisation failed :(\n");                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;			                dvb_ca_en50221_thread_update_delay(ca);                                        break;                                }                                rxbuf = vmalloc(RX_BUFFER_SIZE);                                if (rxbuf == NULL) {                                        printk("dvb_ca: Unable to allocate CAM rx buffer :(\n");                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;				        dvb_ca_en50221_thread_update_delay(ca);                                        break;                                }                                dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);                                ca->pub->slot_ts_enable(ca->pub, slot);                                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;                                dvb_ca_en50221_thread_update_delay(ca);                                printk("dvb_ca: DVB CAM detected and initialised successfully\n");                                break;                        case DVB_CA_SLOTSTATE_RUNNING:                                if (!ca->open) break;                                pktcount = 0;                                while(dvb_ca_en50221_read_data(ca, slot, NULL, 0) > 0) {                                        if (!ca->open) break;                                        /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */                                        if (dvb_ca_en50221_check_camstatus(ca, slot)) {                                                // we dont want to sleep on the next iteration so we can handle the cam change                                                ca->wakeup = 1;                                                break;                                        }                                        /* check if we've hit our limit this time */                                        if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {                                                // dont sleep; there is likely to be more data to read                                                ca->wakeup = 1;                                                break;                                        }                                }                                break;                        }                }        }        /* completed */        ca->thread_pid = 0;        mb();        wake_up_interruptible (&ca->thread_queue);        return 0;}/* ******************************************************************************** *//* EN50221 IO interface functions *//** * Real ioctl implementation. * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. * * @param inode Inode concerned. * @param file File concerned. * @param cmd IOCTL command. * @param arg Associated argument. * * @return 0 on success, <0 on error. */static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg){        struct dvb_device* dvbdev=(struct dvb_device*) file->private_data;        struct dvb_ca_private* ca = (struct dvb_ca_private*) dvbdev->priv;        int err=0;        int slot;        dprintk ("%s\n", __FUNCTION__);        switch (cmd) {        case CA_RESET:                for(slot = 0; slot < ca->slot_count; slot++) {                        if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) {                                dvb_ca_en50221_slot_shutdown(ca, slot);                                if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)                                        dvb_ca_en50221_camchange_irq(ca->pub, slot, DVB_CA_EN50221_CAMCHANGE_INSERTED);                        }                }                ca->next_read_slot = 0;                dvb_ca_en50221_thread_wakeup(ca);                break;        case CA_GET_CAP:        {                struct ca_caps *caps = (struct ca_caps*) parg;                caps->slot_num=ca->slot_count;                caps->slot_type=CA_CI_LINK;                caps->descr_num=0;                caps->descr_type=0;                break;        }        case CA_GET_SLOT_INFO:        {                struct ca_slot_info *info=(struct ca_slot_info *)parg;                if ((info->num > ca->slot_count) || (info->num < 0))                        return -EINVAL;                info->type = CA_CI_LINK;                info->flags = 0;                if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE) &&                    (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) {                        info->flags = CA_CI_MODULE_PRESENT;                }                if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) {                        info->flags |= CA_CI_MODULE_READY;                }                break;        }        default:                err=-EINVAL;                break;        }        return err;}/** * Wrapper for ioctl implementation. * * @param inode Inode concerned. * @param file File concerned. * @param cmd IOCTL command. * @param arg Associated argument. * * @return 0 on success, <0 on error. */static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){        return dvb_usercopy(inode, file, cmd, arg, dvb_ca_en50221_io_do_ioctl);}/** * Implementation of write() syscall. * * @param file File structure. * @param buf Source buffer. * @param count Size of source buffer. * @param ppos Position in file (ignored). * * @return Number of bytes read, or <0 on error. */static ssize_t dvb_ca_en50221_io_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){        struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;        struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv;        u8 slot, connection_id;        int status;        char fragbuf[HOST_LINK_BUF_SIZE];        int fragpos = 0;        size_t fraglen;        unsigned long timeout;        int written;        dprintk ("%s\n", __FUNCTION__);        /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */        if (count < 2) return -EINVAL;        /* extract slot & connection id */        if (copy_from_user(&slot, buf, 1)) return -EFAULT;        if (copy_from_user(&connection_id, buf+1, 1)) return -EFAULT;        buf+=2;        count-=2;        /* check if the slot is actually running */        if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) return -EINVAL;        /* fragment the packets & store in the buffer */        while(fragpos < count) {                fraglen = ca->slot_info[slot].link_buf_size - 2;                if ((count - fragpos) < fraglen) fraglen = count - fragpos;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?