📄 n_hdlc.c
字号:
if (signal_pending(current)) { error = -EINTR; break; } tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); } current->state = TASK_RUNNING; remove_wait_queue(&n_hdlc->write_wait, &wait); } if (!error) { /* Retrieve the user's buffer */ COPY_FROM_USER (error, tbuf->buf, data, count); if (error) { /* return tx buffer to free list */ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf); } else { /* Send the data */ tbuf->count = error = count; n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf); n_hdlc_send_frames(n_hdlc,tty); } } return error; } /* end of n_hdlc_tty_write() *//* n_hdlc_tty_ioctl() * * Process IOCTL system call for the tty device. * * Arguments: * * tty pointer to tty instance data * file pointer to open file object for device * cmd IOCTL command code * arg argument for IOCTL call (cmd dependent) * * Return Value: Command dependent */static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){ struct n_hdlc *n_hdlc = tty2n_hdlc (tty); int error = 0; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_ioctl() called %d\n", __FILE__,__LINE__,cmd); /* Verify the status of the device */ if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC) return -EBADF; switch (cmd) { case FIONREAD: { /* report count of read data available */ /* in next available frame (if any) */ int count; unsigned long flags; spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags); if (n_hdlc->rx_buf_list.head) count = n_hdlc->rx_buf_list.head->count; else count = 0; spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags); PUT_USER (error, count, (int *) arg); } break; default: error = n_tty_ioctl (tty, file, cmd, arg); break; } return error; } /* end of n_hdlc_tty_ioctl() */#if LINUX_VERSION_CODE < VERSION(2,1,23)/* n_hdlc_tty_select() * * Device select method. Determine if operation requires * blocking and if so put appropriate wait queue in select * table and return 0, otherwise return 1. * * Arguments: * * tty pointer to tty device instance data * inode pointer to inode for device * filp pointer to file object * sel_type identified the select type (read/write/exception) * wait select table for adding wait queue if appropriate * * Return Value: * * 1 if no need to block on operation * 0 if must block and wait queue added to select table */static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode, struct file *filp, int sel_type, select_table * wait){ struct n_hdlc *n_hdlc = tty2n_hdlc(tty); int result = 1; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_select() called\n",__FILE__,__LINE__); /* Verify the status of the device */ if (!n_hdlc) return -EBADF; if (n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) return -EBADF; switch (sel_type) { case SEL_IN: if (n_hdlc->rx_buf_list.head) break; case SEL_EX: /* Exceptions or read errors */ /* Is this a pty link and the remote disconnected? */ if (tty->flags & (1 << TTY_OTHER_CLOSED)) break; /* Is this a local link and the modem disconnected? */ if (tty_hung_up_p (filp)) break; select_wait (&n_hdlc->read_wait, wait); result = 0; break; /* Write mode. A write is allowed if there is no current transmission */ case SEL_OUT: if (!n_hdlc->tx_free_buf_list.head) { select_wait (&n_hdlc->write_wait, wait); result = 0; } break; } return result;} /* end of n_hdlc_tty_select() */#else /* 2.1.23 or later *//* n_hdlc_tty_poll() * * TTY callback for poll system call. Determine which * operations (read/write) will not block and return * info to caller. * * Arguments: * * tty pointer to tty instance data * filp pointer to open file object for device * poll_table wait queue for operations * * Return Value: * * bit mask containing info on which ops will not block */static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, struct file *filp, poll_table * wait){ struct n_hdlc *n_hdlc = tty2n_hdlc (tty); unsigned int mask = 0; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__); if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) { /* queue current process into any wait queue that */ /* may awaken in the future (read and write) */#if LINUX_VERSION_CODE < VERSION(2,1,89) poll_wait(&n_hdlc->read_wait, wait); poll_wait(&n_hdlc->write_wait, wait);#else poll_wait(filp, &n_hdlc->read_wait, wait); poll_wait(filp, &n_hdlc->write_wait, wait);#endif /* set bits for operations that wont block */ if(n_hdlc->rx_buf_list.head) mask |= POLLIN | POLLRDNORM; /* readable */ if(tty->flags & (1 << TTY_OTHER_CLOSED)) mask |= POLLHUP; if(tty_hung_up_p(filp)) mask |= POLLHUP; if(n_hdlc->tx_free_buf_list.head) mask |= POLLOUT | POLLWRNORM; /* writable */ } return mask;} /* end of n_hdlc_tty_poll() */#endif/* n_hdlc_alloc() * * Allocate an n_hdlc instance data structure * * Arguments: None * Return Value: pointer to structure if success, otherwise 0 */static struct n_hdlc *n_hdlc_alloc (void){ struct n_hdlc *n_hdlc; N_HDLC_BUF *buf; int i; n_hdlc = (struct n_hdlc *)kmalloc(sizeof(struct n_hdlc), GFP_KERNEL); if (!n_hdlc) return 0; memset(n_hdlc, 0, sizeof(*n_hdlc)); n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list); n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list); n_hdlc_buf_list_init(&n_hdlc->rx_buf_list); n_hdlc_buf_list_init(&n_hdlc->tx_buf_list); /* allocate free rx buffer list */ for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) { buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_KERNEL); if (buf) n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf); } /* allocate free rx buffer list */ for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) { buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_KERNEL); if (buf) n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf); } /* Initialize the control block */ n_hdlc->magic = HDLC_MAGIC; n_hdlc->flags = 0; n_hdlc->read_wait = NULL; n_hdlc->write_wait = NULL; return n_hdlc; } /* end of n_hdlc_alloc() *//* n_hdlc_buf_list_init() * * initialize specified HDLC buffer list * * Arguments: list pointer to buffer list * Return Value: None */void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list){ memset(list,0,sizeof(N_HDLC_BUF_LIST)); } /* end of n_hdlc_buf_list_init() *//* n_hdlc_buf_put() * * add specified HDLC buffer to tail of specified list * * Arguments: * * list pointer to buffer list * buf pointer to buffer * * Return Value: None */void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf){ unsigned long flags; spin_lock_irqsave(&list->spinlock,flags); buf->link=NULL; if(list->tail) list->tail->link = buf; else list->head = buf; list->tail = buf; (list->count)++; spin_unlock_irqrestore(&list->spinlock,flags); } /* end of n_hdlc_buf_put() *//* n_hdlc_buf_get() * * remove and return an HDLC buffer from the * head of the specified HDLC buffer list * * Arguments: * * list pointer to HDLC buffer list * * Return Value: * * pointer to HDLC buffer if available, otherwise NULL */N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list){ unsigned long flags; N_HDLC_BUF *buf; spin_lock_irqsave(&list->spinlock,flags); buf = list->head; if (buf) { list->head = buf->link; (list->count)--; } if (!list->head) list->tail = NULL; spin_unlock_irqrestore(&list->spinlock,flags); return buf; } /* end of n_hdlc_buf_get() *//* init_module() * * called when module is loading to register line discipline * * Arguments: None * Return Value: 0 if success, otherwise error code */int init_module(void){ static struct tty_ldisc n_hdlc_ldisc; int status; printk("HDLC line discipline: version %s\n", szVersion); /* Register the tty discipline */ memset(&n_hdlc_ldisc, 0, sizeof (n_hdlc_ldisc)); n_hdlc_ldisc.magic = TTY_LDISC_MAGIC;#if LINUX_VERSION_CODE >= VERSION(2,1,28) n_hdlc_ldisc.name = "hdlc";#endif n_hdlc_ldisc.open = n_hdlc_tty_open; n_hdlc_ldisc.close = n_hdlc_tty_close; n_hdlc_ldisc.read = n_hdlc_tty_read; n_hdlc_ldisc.write = n_hdlc_tty_write; n_hdlc_ldisc.ioctl = n_hdlc_tty_ioctl;#if LINUX_VERSION_CODE < VERSION(2,1,23) n_hdlc_ldisc.select = n_hdlc_tty_select;#else n_hdlc_ldisc.poll = n_hdlc_tty_poll;#endif n_hdlc_ldisc.receive_room = n_hdlc_tty_room; n_hdlc_ldisc.receive_buf = n_hdlc_tty_receive; n_hdlc_ldisc.write_wakeup = n_hdlc_tty_wakeup; status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc); if (!status) printk (KERN_INFO"N_HDLC line discipline registered.\n"); else printk (KERN_ERR"error registering line discipline: %d\n",status); if (status) printk(KERN_INFO"N_HDLC: init failure %d\n", status); return (status); } /* end of init_module() *//* cleanup_module() * * called when module is unloading to unregister line discipline * * Arguments: None * Return Value: None */void cleanup_module(void){ int status; /* Release tty registration of line discipline */ if ((status = tty_register_ldisc(N_HDLC, NULL))) printk("N_HDLC: can't unregister line discipline (err = %d)\n", status); else printk("N_HDLC: line discipline unregistered\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -