📄 dvb_ca_en50221.c
字号:
/* check the CAM hasn't been removed/reset in the meantime */ if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) { status = -EIO; goto exit; } status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen+2); if (status == (fraglen+2)) { written = 1; break; } if (status != -EAGAIN) goto exit; msleep(1); } if (!written) { status = -EIO; goto exit; } fragpos += fraglen; } status = count + 2;exit: return status;}/** * Condition for waking up in dvb_ca_en50221_io_read_condition */static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private* ca, int* result, int* _slot){ int slot; int slot_count = 0; int idx; int fraglen; int connection_id = -1; int found = 0; u8 hdr[2]; slot = ca->next_read_slot; while((slot_count < ca->slot_count) && (!found)) { if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) goto nextslot; down_read(&ca->slot_info[slot].sem); if (ca->slot_info[slot].rx_buffer.data == NULL) { up_read(&ca->slot_info[slot].sem); return 0; } 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); if (connection_id == -1) connection_id = hdr[0]; if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) { *_slot = slot; found = 1; break; } idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); } if (!found) up_read(&ca->slot_info[slot].sem);nextslot: slot = (slot + 1) % ca->slot_count; slot_count++; } ca->next_read_slot = slot; return found;}/** * Implementation of read() syscall. * * @param file File structure. * @param buf Destination buffer. * @param count Size of destination buffer. * @param ppos Position in file (ignored). * * @return Number of bytes read, or <0 on error. */static ssize_t dvb_ca_en50221_io_read(struct file *file, 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; int status; int result = 0; u8 hdr[2]; int slot; int connection_id = -1; size_t idx, idx2; int last_fragment = 0; size_t fraglen; int pktlen; int dispose = 0; dprintk ("%s\n", __FUNCTION__); /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ if (count < 2) return -EINVAL; /* wait for some data */ if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) { /* if we're in nonblocking mode, exit immediately */ if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; /* wait for some data */ status = wait_event_interruptible(ca->wait_queue, dvb_ca_en50221_io_read_condition (ca, &result, &slot)); } if ((status < 0) || (result < 0)) { if (result) return result; return status; } idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); pktlen = 2; do { if (idx == -1) { printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num); status = -EIO; goto exit; } dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0); if (connection_id == -1) connection_id = hdr[0]; if (hdr[0] == connection_id) { if (pktlen < count) { if ((pktlen + fraglen - 2) > count) { fraglen = count - pktlen; } else { fraglen -= 2; } if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2, buf + pktlen, fraglen, 1)) < 0) { goto exit; } pktlen += fraglen; } if ((hdr[1] & 0x80) == 0) last_fragment = 1; dispose = 1; } idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); if (dispose) dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx); idx = idx2; dispose = 0; } while (!last_fragment); hdr[0] = slot; hdr[1] = connection_id; if ((status = copy_to_user(buf, hdr, 2)) != 0) goto exit; status = pktlen;exit: up_read(&ca->slot_info[slot].sem); return status;}/** * Implementation of file open syscall. * * @param inode Inode concerned. * @param file File concerned. * * @return 0 on success, <0 on failure. */static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file){ struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; struct dvb_ca_private *ca = (struct dvb_ca_private*) dvbdev->priv; int err; int i; dprintk ("%s\n", __FUNCTION__); if (!try_module_get(ca->pub->owner)) return -EIO; err=dvb_generic_open(inode, file); if (err<0) return err; for(i=0; i< ca->slot_count; i++) { if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { down_write(&ca->slot_info[i].sem); if (ca->slot_info[i].rx_buffer.data != NULL) { dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); } up_write(&ca->slot_info[i].sem); } } ca->open = 1; dvb_ca_en50221_thread_update_delay(ca); dvb_ca_en50221_thread_wakeup(ca); return 0;}/** * Implementation of file close syscall. * * @param inode Inode concerned. * @param file File concerned. * * @return 0 on success, <0 on failure. */static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file){ struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv; int err = 0; dprintk ("%s\n", __FUNCTION__); /* mark the CA device as closed */ ca->open = 0; dvb_ca_en50221_thread_update_delay(ca); err=dvb_generic_release(inode, file); module_put(ca->pub->owner); return 0;}/** * Implementation of poll() syscall. * * @param file File concerned. * @param wait poll wait table. * * @return Standard poll mask. */static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait){ struct dvb_device* dvbdev = (struct dvb_device*) file->private_data; struct dvb_ca_private* ca = (struct dvb_ca_private*) dvbdev->priv; unsigned int mask=0; int slot; int result = 0; dprintk ("%s\n", __FUNCTION__); if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { up_read(&ca->slot_info[slot].sem); mask |= POLLIN; } /* if there is something, return now */ if (mask) return mask; /* wait for something to happen */ poll_wait(file, &ca->wait_queue, wait); if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { up_read(&ca->slot_info[slot].sem); mask |= POLLIN; } return mask;}EXPORT_SYMBOL(dvb_ca_en50221_init);static struct file_operations dvb_ca_fops = { .owner = THIS_MODULE, .read = dvb_ca_en50221_io_read, .write = dvb_ca_en50221_io_write, .ioctl = dvb_ca_en50221_io_ioctl, .open = dvb_ca_en50221_io_open, .release= dvb_ca_en50221_io_release, .poll = dvb_ca_en50221_io_poll,};static struct dvb_device dvbdev_ca = { .priv = NULL, .users = 1, .readers= 1, .writers= 1, .fops = &dvb_ca_fops,};/* ******************************************************************************** *//* Initialisation/shutdown functions *//** * Initialise a new DVB CA EN50221 interface device. * * @param dvb_adapter DVB adapter to attach the new CA device to. * @param ca The dvb_ca instance. * @param flags Flags describing the CA device (DVB_CA_FLAG_*). * @param slot_count Number of slots supported. * * @return 0 on success, nonzero on failure */int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221 *pubca, int flags, int slot_count){ int ret; struct dvb_ca_private* ca = NULL; int i; dprintk ("%s\n", __FUNCTION__); if (slot_count < 1) return -EINVAL; /* initialise the system data */ if ((ca = (struct dvb_ca_private *) kmalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { ret = -ENOMEM; goto error; } memset(ca, 0, sizeof(struct dvb_ca_private)); ca->pub = pubca; ca->flags = flags; ca->slot_count = slot_count; if ((ca->slot_info = kmalloc(sizeof(struct dvb_ca_slot) * slot_count, GFP_KERNEL)) == NULL) { ret = -ENOMEM; goto error; } memset(ca->slot_info, 0, sizeof(struct dvb_ca_slot) * slot_count); 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; pubca->private = ca; /* register the DVB device */ ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA); if (ret) goto error; /* now initialise each slot */ for(i=0; i< slot_count; i++) { memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot)); ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; atomic_set(&ca->slot_info[i].camchange_count, 0); ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; init_rwsem(&ca->slot_info[i].sem); } if (signal_pending(current)) { ret = -EINTR; goto error; } 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); goto error; } ca->thread_pid = ret; return 0;error: if (ca != NULL) { if (ca->dvbdev != NULL) dvb_unregister_device(ca->dvbdev); if (ca->slot_info != NULL) kfree(ca->slot_info); kfree(ca); } pubca->private = NULL; return ret;}EXPORT_SYMBOL(dvb_ca_en50221_release);/** * Release a DVB CA EN50221 interface device. * * @param ca_dev The dvb_device_t instance for the CA device. * @param ca The associated dvb_ca instance. */void dvb_ca_en50221_release(struct dvb_ca_en50221* pubca){ struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private; int i; dprintk ("%s\n", __FUNCTION__); /* 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); } } for(i=0; i< ca->slot_count; i++) { dvb_ca_en50221_slot_shutdown(ca, i); } kfree(ca->slot_info); dvb_unregister_device(ca->dvbdev); kfree(ca); pubca->private = NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -