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

📄 n_hdlc.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (debuglevel >= DEBUG_LEVEL_INFO)			printk("%s(%d)n_hdlc_tty_open() called\n",__FILE__,__LINE__);			/* There should not be an existing table for this slot. */	if (n_hdlc) {		printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" );		return -EEXIST;	}		n_hdlc = n_hdlc_alloc();	if (!n_hdlc) {		printk (KERN_ERR "n_hdlc_alloc failed\n");		return -ENFILE;	}			tty->disc_data = n_hdlc;	n_hdlc->tty    = tty;			MOD_INC_USE_COUNT;		/* Flush any pending characters in the driver and discipline. */		if (tty->ldisc.flush_buffer)		tty->ldisc.flush_buffer (tty);	if (tty->driver.flush_buffer)		tty->driver.flush_buffer (tty);			if (debuglevel >= DEBUG_LEVEL_INFO)			printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);			return 0;	}	/* end of n_tty_hdlc_open() *//* n_hdlc_send_frames() *  * 	send frames on pending send buffer list until the * 	driver does not accept a frame (busy) * 	this function is called after adding a frame to the * 	send buffer list and by the tty wakeup callback * 	 * Arguments:		n_hdlc		pointer to ldisc instance data * 			tty		pointer to tty instance data * Return Value:	None */static void n_hdlc_send_frames (struct n_hdlc *n_hdlc, struct tty_struct *tty){	register int actual;	unsigned long flags;	N_HDLC_BUF *tbuf;		if (debuglevel >= DEBUG_LEVEL_INFO)			printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);			save_flags(flags);	cli ();	if (n_hdlc->tbusy) {		n_hdlc->woke_up = 1;		restore_flags(flags);		return;	}	n_hdlc->tbusy = 1;	restore_flags(flags);	/* get current transmit buffer or get new transmit */	/* buffer from list of pending transmit buffers */			tbuf = n_hdlc->tbuf;	if (!tbuf)		tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);			while (tbuf) {		if (debuglevel >= DEBUG_LEVEL_INFO)				printk("%s(%d)sending frame %p, count=%d\n",				__FILE__,__LINE__,tbuf,tbuf->count);					/* Send the next block of data to device */		n_hdlc->woke_up = 0;		tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);		actual = tty->driver.write(tty, 0, tbuf->buf, tbuf->count);		    		/* if transmit error, throw frame away by */		/* pretending it was accepted by driver */		if (actual < 0)			actual = tbuf->count;				if (actual == tbuf->count) {			if (debuglevel >= DEBUG_LEVEL_INFO)					printk("%s(%d)frame %p completed\n",					__FILE__,__LINE__,tbuf);								/* free current transmit buffer */			n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf);						/* this tx buffer is done */			n_hdlc->tbuf = NULL;						/* wait up sleeping writers */			wake_up_interruptible(&n_hdlc->write_wait);				/* get next pending transmit buffer */			tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);		} else {			if (debuglevel >= DEBUG_LEVEL_INFO)					printk("%s(%d)frame %p pending\n",					__FILE__,__LINE__,tbuf);								/* buffer not accepted by driver */						/* check if wake up code called since last write call */			if (n_hdlc->woke_up)				continue;							/* set this buffer as pending buffer */			n_hdlc->tbuf = tbuf;			break;		}	}		if (!tbuf)		tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);		/* Clear the re-entry flag */	save_flags(flags);	cli ();	n_hdlc->tbusy = 0;	restore_flags(flags);		if (debuglevel >= DEBUG_LEVEL_INFO)			printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);		}	/* end of n_hdlc_send_frames() *//* n_hdlc_tty_wakeup() * *	Callback for transmit wakeup. Called when low level *	device driver can accept more send data. * * Arguments:		tty	pointer to associated tty instance data * Return Value:	None */static void n_hdlc_tty_wakeup (struct tty_struct *tty){	struct n_hdlc *n_hdlc = tty2n_hdlc (tty);	if (debuglevel >= DEBUG_LEVEL_INFO)			printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__);			if (!n_hdlc)		return;	if (tty != n_hdlc->tty) {		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);		return;	}		if (!n_hdlc->tbuf)		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);	else		n_hdlc_send_frames (n_hdlc, tty);		}	/* end of n_hdlc_tty_wakeup() *//* n_hdlc_tty_room() *  *	Callback function from tty driver. Return the amount of  *	space left in the receiver's buffer to decide if remote *	transmitter is to be throttled. * * Arguments:		tty	pointer to associated tty instance data * Return Value:	number of bytes left in receive buffer */static int n_hdlc_tty_room (struct tty_struct *tty){	if (debuglevel >= DEBUG_LEVEL_INFO)			printk("%s(%d)n_hdlc_tty_room() called\n",__FILE__,__LINE__);	/* always return a larger number to prevent */	/* throttling of remote transmitter. */	return 65536;}	/* end of n_hdlc_tty_root() *//* n_hdlc_tty_receive() *  * 	Called by tty low level driver when receive data is * 	available. Data is interpreted as one HDLC frame. * 	 * 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;	}		/* 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(sizeof(N_HDLC_BUF),GFP_ATOMIC);	}		if (!buf) {		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);	if (n_hdlc->tty->fasync != NULL)		kill_fasync (n_hdlc->tty->fasync, SIGIO);}	/* 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;					/* TODO: no timeout? current->timeout = 0;*/		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;	struct wait_queue wait = {current, NULL};	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 > MAX_HDLC_FRAME_SIZE) {		if (debuglevel & DEBUG_LEVEL_INFO)			printk (KERN_WARNING				"n_hdlc_tty_write: truncating user packet "				"from %lu to %d\n", (unsigned long) count,				MAX_HDLC_FRAME_SIZE);		count = MAX_HDLC_FRAME_SIZE;	}		/* Allocate transmit buffer */	tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);	if (!tbuf) {		/* sleep until transmit buffer available */				add_wait_queue(&n_hdlc->write_wait, &wait);		while (!tbuf) {			/* TODO: no timeout? current->timeout = 0;*/			current->state = TASK_INTERRUPTIBLE;			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;			}			

⌨️ 快捷键说明

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