⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dvb_ca_en50221.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
                break;        case DVB_CA_SLOTSTATE_RUNNING:		if (ca->open)			dvb_ca_en50221_read_data(ca, slot, NULL, 0);                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 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 ();        /* 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 adaptor %d: PC card did not respond :(\n",					       ca->dvbdev->adapter->num);                                        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 adapter %d: Invalid PC card inserted :(\n",					       ca->dvbdev->adapter->num);                                        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 adapter %d: Unable to initialise CAM :(\n",					       ca->dvbdev->adapter->num);                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;				        dvb_ca_en50221_thread_update_delay(ca);                                        break;                                }				if (ca->pub->write_cam_control(ca->pub, slot,							       CTRLIF_COMMAND, CMDREG_RS) != 0) {					printk("dvb_ca adapter %d: Unable to reset CAM IF\n",					       ca->dvbdev->adapter->num);                                        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 adapter %d: DVB CAM did not respond :(\n",					       ca->dvbdev->adapter->num);                                        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 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);                                        break;                                }                                rxbuf = vmalloc(RX_BUFFER_SIZE);                                if (rxbuf == NULL) {                                        printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num);                                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;				        dvb_ca_en50221_thread_update_delay(ca);                                        break;                                }				down_write(&ca->slot_info[slot].sem);                                dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);				up_write(&ca->slot_info[slot].sem);                                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 adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num);                                break;                        case DVB_CA_SLOTSTATE_RUNNING:				if (!ca->open)					continue;				// no need to poll if the CAM supports IRQs				if (ca->slot_info[slot].da_irq_supported)					break;				// poll mode                                pktcount = 0;				while ((status = 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;        int 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;                fragbuf[0] = connection_id;                fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;		if ((status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen)) != 0)			goto exit;		timeout = jiffies + HZ/2;	        written = 0;                while(!time_after(jiffies, timeout)) {

⌨️ 快捷键说明

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