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

📄 n_hdlc.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
 * 	 * Arguments:	 	tty		pointer to tty isntance data * 			data		pointer to received data * 			flags		pointer to flags for data * 			count		count of received data in bytes * 	 * Return Value:	None */static void n_hdlc_tty_receive(struct tty_struct *tty,	const __u8 * data, char *flags, int count){	register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);	register N_HDLC_BUF *buf;	if (debuglevel >= DEBUG_LEVEL_INFO)			printk("%s(%d)n_hdlc_tty_receive() called count=%d\n",			__FILE__,__LINE__, count);			/* This can happen if stuff comes in on the backup tty */	if (n_hdlc == 0 || tty != n_hdlc->tty)		return;			/* verify line is using HDLC discipline */	if (n_hdlc->magic != HDLC_MAGIC) {		printk("%s(%d) line not using HDLC discipline\n",			__FILE__,__LINE__);		return;	}		if ( count>maxframe ) {		if (debuglevel >= DEBUG_LEVEL_INFO)				printk("%s(%d) rx count>maxframesize, data discarded\n",			       __FILE__,__LINE__);		return;	}	/* get a free HDLC buffer */		buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);	if (!buf) {		/* no buffers in free list, attempt to allocate another rx buffer */		/* unless the maximum count has been reached */		if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)			buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_ATOMIC);	}		if (!buf) {		if (debuglevel >= DEBUG_LEVEL_INFO)				printk("%s(%d) no more rx buffers, data discarded\n",			       __FILE__,__LINE__);		return;	}			/* copy received data to HDLC buffer */	memcpy(buf->buf,data,count);	buf->count=count;	/* add HDLC buffer to list of received frames */	n_hdlc_buf_put(&n_hdlc->rx_buf_list,buf);		/* wake up any blocked reads and perform async signalling */	wake_up_interruptible (&n_hdlc->read_wait);	wake_up_interruptible (&n_hdlc->poll_wait);	if (n_hdlc->tty->fasync != NULL)		kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);}	/* end of n_hdlc_tty_receive() *//* n_hdlc_tty_read() *  * 	Called to retreive one frame of data (if available) * 	 * Arguments: *  * 	tty		pointer to tty instance data * 	file		pointer to open file object * 	buf		pointer to returned data buffer * 	nr		size of returned data buffer * 	 * Return Value: *  * 	Number of bytes returned or error code */static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty,	struct file *file, __u8 * buf, rw_count_t nr){	struct n_hdlc *n_hdlc = tty2n_hdlc(tty);	int error;	rw_ret_t ret;	N_HDLC_BUF *rbuf;	if (debuglevel >= DEBUG_LEVEL_INFO)			printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);			/* Validate the pointers */	if (!n_hdlc)		return -EIO;	/* verify user access to buffer */	error = verify_area (VERIFY_WRITE, buf, nr);	if (error != 0) {		printk(KERN_WARNING"%s(%d) n_hdlc_tty_read() can't verify user "		"buffer\n",__FILE__,__LINE__);		return (error);	}	for (;;) {		n_hdlc = tty2n_hdlc (tty);		if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||			 tty != n_hdlc->tty)			return 0;		rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);		if (rbuf)			break;					/* no data */		if (file->f_flags & O_NONBLOCK)			return -EAGAIN;					interruptible_sleep_on (&n_hdlc->read_wait);		if (signal_pending(current))			return -EINTR;	}			if (rbuf->count > nr) {		/* frame too large for caller's buffer (discard frame) */		ret = (rw_ret_t)-EOVERFLOW;	} else {		/* Copy the data to the caller's buffer */		COPY_TO_USER(error,buf,rbuf->buf,rbuf->count);		if (error)			ret = (rw_ret_t)error;		else			ret = (rw_ret_t)rbuf->count;	}		/* return HDLC buffer to free list unless the free list */	/* count has exceeded the default value, in which case the */	/* buffer is freed back to the OS to conserve memory */	if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)		kfree(rbuf);	else			n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);		return ret;	}	/* end of n_hdlc_tty_read() *//* n_hdlc_tty_write() *  * 	write a single frame of data to device * 	 * Arguments:	tty	pointer to associated tty device instance data * 		file	pointer to file object data * 		data	pointer to transmit data (one frame) * 		count	size of transmit frame in bytes * 		 * Return Value:	number of bytes written (or error code) */static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,	const __u8 * data, rw_count_t count){	struct n_hdlc *n_hdlc = tty2n_hdlc (tty);	int error = 0;	DECLARE_WAITQUEUE(wait, current);	N_HDLC_BUF *tbuf;	if (debuglevel >= DEBUG_LEVEL_INFO)			printk("%s(%d)n_hdlc_tty_write() called count=%d\n",			__FILE__,__LINE__,count);			/* Verify pointers */	if (!n_hdlc)		return -EIO;	if (n_hdlc->magic != HDLC_MAGIC)		return -EIO;	/* verify frame size */	if (count > maxframe ) {		if (debuglevel & DEBUG_LEVEL_INFO)			printk (KERN_WARNING				"n_hdlc_tty_write: truncating user packet "				"from %lu to %d\n", (unsigned long) count,				maxframe );		count = maxframe;	}		add_wait_queue(&n_hdlc->write_wait, &wait);	set_current_state(TASK_INTERRUPTIBLE);		/* Allocate transmit buffer */	/* sleep until transmit buffer available */			while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {		schedule();					n_hdlc = tty2n_hdlc (tty);		if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || 		    tty != n_hdlc->tty) {			printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);			error = -EIO;			break;		}					if (signal_pending(current)) {			error = -EINTR;			break;		}	}	set_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;	int count;	unsigned long flags;		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) */		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;	case TIOCOUTQ:		/* get the pending tx byte count in the driver */		count = tty->driver.chars_in_buffer ?				tty->driver.chars_in_buffer(tty) : 0;		/* add size of next output frame in queue */		spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);		if (n_hdlc->tx_buf_list.head)			count += n_hdlc->tx_buf_list.head->count;		spin_unlock_irqrestore(&n_hdlc->tx_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() *//* 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) */		poll_wait(filp, &n_hdlc->poll_wait, wait);		/* 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() *//* 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(N_HDLC_BUF_SIZE,GFP_KERNEL);		if (buf)			n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);		else if (debuglevel >= DEBUG_LEVEL_INFO)				printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);	}		/* allocate free tx buffer list */	for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {		buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_KERNEL);		if (buf)			n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);		else if (debuglevel >= DEBUG_LEVEL_INFO)				printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);	}		/* Initialize the control block */	n_hdlc->magic  = HDLC_MAGIC;	n_hdlc->flags  = 0;	init_waitqueue_head(&n_hdlc->read_wait);	init_waitqueue_head(&n_hdlc->poll_wait);	init_waitqueue_head(&n_hdlc->write_wait);		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));	spin_lock_init(&list->spinlock);}	/* 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() */static int __init n_hdlc_init(void){	static struct tty_ldisc	n_hdlc_ldisc;	int    status;	/* range check maxframe arg */	if ( maxframe<4096)		maxframe=4096;	else if ( maxframe>65535)		maxframe=65535;	printk("HDLC line discipline: version %s, maxframe=%u\n", 		szVersion, maxframe);	/* Register the tty discipline */		memset(&n_hdlc_ldisc, 0, sizeof (n_hdlc_ldisc));	n_hdlc_ldisc.magic		= TTY_LDISC_MAGIC;	n_hdlc_ldisc.name          	= "hdlc";	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;	n_hdlc_ldisc.poll		= n_hdlc_tty_poll;	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() */static void __exit n_hdlc_exit(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");}module_init(n_hdlc_init);module_exit(n_hdlc_exit);

⌨️ 快捷键说明

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