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

📄 n_hdlc.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
			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 + -