📄 capi.c
字号:
retval = copy_to_user((void *) arg, (void *) &data.profile.ncontroller, sizeof(data.profile.ncontroller)); } else { cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile); if (cdev->errcode) return -EIO; retval = copy_to_user((void *) arg, (void *) &data.profile, sizeof(data.profile)); } if (retval) return -EFAULT; } return 0; case CAPI_GET_MANUFACTURER: { retval = copy_from_user((void *) &data.contr, (void *) arg, sizeof(data.contr)); if (retval) return -EFAULT; cdev->errcode = (*capifuncs->capi_get_manufacturer) (data.contr, data.manufacturer); if (cdev->errcode) return -EIO; retval = copy_to_user((void *) arg, (void *) data.manufacturer, sizeof(data.manufacturer)); if (retval) return -EFAULT; } return 0; case CAPI_GET_ERRCODE: data.errcode = cdev->errcode; cdev->errcode = CAPI_NOERROR; if (arg) { retval = copy_to_user((void *) arg, (void *) &data.errcode, sizeof(data.errcode)); if (retval) return -EFAULT; } return data.errcode; case CAPI_INSTALLED: if ((*capifuncs->capi_isinstalled)() == CAPI_NOERROR) return 0; return -ENXIO; case CAPI_MANUFACTURER_CMD: { struct capi_manufacturer_cmd mcmd; if (!capable(CAP_SYS_ADMIN)) return -EPERM; retval = copy_from_user((void *) &mcmd, (void *) arg, sizeof(mcmd)); if (retval) return -EFAULT; return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data); } return 0; case CAPI_SET_FLAGS: case CAPI_CLR_FLAGS: { unsigned userflags; retval = copy_from_user((void *) &userflags, (void *) arg, sizeof(userflags)); if (retval) return -EFAULT; if (cmd == CAPI_SET_FLAGS) cdev->userflags |= userflags; else cdev->userflags &= ~userflags; } return 0; case CAPI_GET_FLAGS: { retval = copy_to_user((void *) arg, (void *) &cdev->userflags, sizeof(cdev->userflags)); if (retval) return -EFAULT; } return 0; case CAPI_NCCI_OPENCOUNT: { struct capincci *nccip;#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE struct capiminor *mp;#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ unsigned ncci; int count = 0; retval = copy_from_user((void *) &ncci, (void *) arg, sizeof(ncci)); if (retval) return -EFAULT; nccip = capincci_find(cdev, (__u32) ncci); if (!nccip) return 0;#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if ((mp = nccip->minorp) != 0) { count += atomic_read(&mp->ttyopencount); if (mp->file) count++; }#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ return count; } return 0;#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE case CAPI_NCCI_GETUNIT: { struct capincci *nccip; struct capiminor *mp; unsigned ncci; retval = copy_from_user((void *) &ncci, (void *) arg, sizeof(ncci)); if (retval) return -EFAULT; nccip = capincci_find(cdev, (__u32) ncci); if (!nccip || (mp = nccip->minorp) == 0) return -ESRCH; return mp->minor; } return 0;#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ } return -EINVAL;}static intcapi_open(struct inode *inode, struct file *file){ if (file->private_data) return -EEXIST; if ((file->private_data = capidev_alloc(file)) == 0) return -ENOMEM; MOD_INC_USE_COUNT;#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(THIS_MODULE));#endif return 0;}static intcapi_release(struct inode *inode, struct file *file){ struct capidev *cdev = (struct capidev *)file->private_data; lock_kernel(); capincci_free(cdev, 0xffffffff); capidev_free(cdev); file->private_data = NULL; MOD_DEC_USE_COUNT;#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE));#endif unlock_kernel(); return 0;}static struct file_operations capi_fops ={ owner: THIS_MODULE, llseek: capi_llseek, read: capi_read, write: capi_write, poll: capi_poll, ioctl: capi_ioctl, open: capi_open, release: capi_release,};#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE/* -------- file_operations for capincci ---------------------------- */static intcapinc_raw_open(struct inode *inode, struct file *file){ struct capiminor *mp; if (file->private_data) return -EEXIST; if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0) return -ENXIO; if (mp->nccip == 0) return -ENXIO; if (mp->file) return -EBUSY;#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_raw_open %d\n", GET_USE_COUNT(THIS_MODULE));#endif mp->datahandle = 0; mp->file = file; file->private_data = (void *)mp; handle_minor_recv(mp); return 0;}static loff_tcapinc_raw_llseek(struct file *file, loff_t offset, int origin){ return -ESPIPE;}static ssize_tcapinc_raw_read(struct file *file, char *buf, size_t count, loff_t *ppos){ struct capiminor *mp = (struct capiminor *)file->private_data; struct sk_buff *skb; int retval; size_t copied = 0; if (ppos != &file->f_pos) return -ESPIPE; if (!mp || !mp->nccip) return -EINVAL; if ((skb = skb_dequeue(&mp->recvqueue)) == 0) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; for (;;) { interruptible_sleep_on(&mp->recvwait); if (mp->nccip == 0) return 0; if ((skb = skb_dequeue(&mp->recvqueue)) != 0) break; if (signal_pending(current)) break; } if (skb == 0) return -ERESTARTNOHAND; } do { if (count < skb->len) { retval = copy_to_user(buf, skb->data, count); if (retval) { skb_queue_head(&mp->recvqueue, skb); return retval; } skb_pull(skb, count); skb_queue_head(&mp->recvqueue, skb); copied += count; return copied; } else { retval = copy_to_user(buf, skb->data, skb->len); if (retval) { skb_queue_head(&mp->recvqueue, skb); return copied; } copied += skb->len; count -= skb->len; buf += skb->len; kfree_skb(skb); } } while ((skb = skb_dequeue(&mp->recvqueue)) != 0); return copied;}static ssize_tcapinc_raw_write(struct file *file, const char *buf, size_t count, loff_t *ppos){ struct capiminor *mp = (struct capiminor *)file->private_data; struct sk_buff *skb; int retval; if (ppos != &file->f_pos) return -ESPIPE; if (!mp || !mp->nccip) return -EINVAL; skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_USER); skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { kfree_skb(skb); return retval; } while (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; interruptible_sleep_on(&mp->sendwait); if (mp->nccip == 0) { kfree_skb(skb); return -EIO; } if (signal_pending(current)) return -ERESTARTNOHAND; } skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; (void)handle_minor_send(mp); return count;}static unsigned intcapinc_raw_poll(struct file *file, poll_table * wait){ struct capiminor *mp = (struct capiminor *)file->private_data; unsigned int mask = 0; if (!mp || !mp->nccip) return POLLERR|POLLHUP; poll_wait(file, &(mp->recvwait), wait); if (!skb_queue_empty(&mp->recvqueue)) mask |= POLLIN | POLLRDNORM; poll_wait(file, &(mp->sendwait), wait); if (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) mask = POLLOUT | POLLWRNORM; return mask;}static intcapinc_raw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct capiminor *mp = (struct capiminor *)file->private_data; if (!mp || !mp->nccip) return -EINVAL; switch (cmd) { } return -EINVAL;}static intcapinc_raw_release(struct inode *inode, struct file *file){ struct capiminor *mp = (struct capiminor *)file->private_data; if (mp) { lock_kernel(); mp->file = 0; if (mp->nccip == 0) { capiminor_free(mp); file->private_data = NULL; } unlock_kernel(); }#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_raw_release %d\n", GET_USE_COUNT(THIS_MODULE));#endif return 0;}static struct file_operations capinc_raw_fops ={ owner: THIS_MODULE, llseek: capinc_raw_llseek, read: capinc_raw_read, write: capinc_raw_write, poll: capinc_raw_poll, ioctl: capinc_raw_ioctl, open: capinc_raw_open, release: capinc_raw_release,};/* -------- tty_operations for capincci ----------------------------- */int capinc_tty_open(struct tty_struct * tty, struct file * file){ struct capiminor *mp; if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0) return -ENXIO; if (mp->nccip == 0) return -ENXIO; if (mp->file) return -EBUSY; skb_queue_head_init(&mp->recvqueue); init_waitqueue_head(&mp->recvwait); init_waitqueue_head(&mp->sendwait); tty->driver_data = (void *)mp;#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_tty_open %d\n", GET_USE_COUNT(THIS_MODULE));#endif if (atomic_read(&mp->ttyopencount) == 0) mp->tty = tty; atomic_inc(&mp->ttyopencount);#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount));#endif handle_minor_recv(mp); return 0;}void capinc_tty_close(struct tty_struct * tty, struct file * file){ struct capiminor *mp; mp = (struct capiminor *)tty->driver_data; if (mp) { if (atomic_dec_and_test(&mp->ttyopencount)) {#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_tty_close lastclose\n");#endif tty->driver_data = (void *)0; mp->tty = 0; }#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));#endif if (mp->nccip == 0) capiminor_free(mp); }#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_tty_close\n");#endif}int capinc_tty_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count){ struct capiminor *mp = (struct capiminor *)tty->driver_data; struct sk_buff *skb; int retval;#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_write(from_user=%d,count=%d)\n", from_user, count);#endif if (!mp || !mp->nccip) {#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n");#endif return 0; } skb = mp->ttyskb; if (skb) { mp->ttyskb = 0; skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; } skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC); if (!skb) { printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n"); return -ENOMEM; } skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); if (from_user) { if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { kfree_skb(skb);#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_write: copy_from_user=%d\n", retval);#endif return retval; } } else { memcpy(skb_put(skb, count), buf, count); } skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; (void)handle_minor_send(mp); (void)handle_minor_recv(mp); return count;}void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch){ struct capiminor *mp = (struct capiminor *)tty->driver_data; struct sk_buff *skb;#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);#endif if (!mp || !mp->nccip) {#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");#endif return; } skb = mp->ttyskb; if (skb) { if (skb_tailroom(skb) > 0) { *(skb_put(skb, 1)) = ch; return; } mp->ttyskb = 0; skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; (void)handle_minor_send(mp); } skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC); if (skb) { skb_reserve(skb, CAPI_DATA_B3_REQ_LEN); *(skb_put(skb, 1)) = ch; mp->ttyskb = skb; } else { printk(KERN_ERR "capinc_put_char: char %u lost\n", ch); }}void capinc_tty_flush_chars(struct tty_struct *tty){ struct capiminor *mp = (struct capiminor *)tty->driver_data; struct sk_buff *skb;#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_flush_chars\n");#endif if (!mp || !mp->nccip) {#ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n");#endif return; } skb = mp->ttyskb; if (skb) { mp->ttyskb = 0; skb_queue_tail(&mp->outqueue, skb); mp->outbytes += skb->len; (void)handle_minor_send(mp); } (void)handle_minor_recv(mp);}int capinc_tty_write_room(struct tty_struct *tty){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -