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

📄 ussp.c

📁 驱动框架:在应用程序空间书写设备驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
}static void ussp_tty_put_char (struct tty_struct * tty, unsigned char ch){	char tempchar = ch;	int count;	func_enter ();	/* Ignore error if there's no space in the buffer (see rs_put_char) */	count = ussp_tty_write (tty, &tempchar, 1);	ussp_dprintk (DEBUG_WRITE_TO_CTL, "writing char: %c %d\n", ch, count);	func_exit ();	return;}static int ussp_tty_open (struct tty_struct *tty, struct file * filp){  	struct ussp_port *port;	struct ussp_operation op;	int line;	func_enter();//	MOD_INC_USE_COUNT;//!!!	line = MINOR (tty->device);	line = tty->index;	ussp_dprintk (1, "%d: opening line %d, tty=%p ctty=%p)\n",		      current->pid, line, tty, current->signal->tty);	port = & ussp_ports[line];	if (!(port->flags & USSP_DEAMON_PRESENT)) {		ussp_dprintk(DEBUG_OPEN, "no deamon. Flags: %x\n",			     port->flags);		func_exit ();		return -ENODEV;	}	port->tty = tty;	tty->driver_data = port;	/* The userspace deamon will already packetize the dataflow,	   so we don't need to introduce extra delay here in the driver. */	if (ussp_set_lowlatency)		tty->low_latency = 1;	ussp_dprintk (DEBUG_OPEN, "Nusers = %d.\n", port->nusers);	port->nusers++;	if (port->nusers > 1)		return 0;	port->callout_termios = tty_std_termios;	port->normal_termios = tty_std_termios; 	op.op = USSP_OPEN;	op.len = 0;	op.arg = filp->f_flags;//!!!	if (MAJOR(tty->device) == USSP_CALLOUT_MAJOR)//!!!		op.arg |= USSP_ISCALLOUT;	copy_to_circular_buffer(port->daemon_buffer, PAGE_SIZE,				&port->daemon_head, &port->daemon_tail,				&op, sizeof (op), 0);	ussp_dprintk(DEBUG_OPEN, "Waking up daemon_wait\n");	wake_up(&port->daemon_wait);	while ((!TTY_DATA_AVAILABLE(port)) &&	       (port->flags & USSP_DEAMON_PRESENT)) {		interruptible_sleep_on (&port->tty_wait);		ussp_dprintk (DEBUG_OPEN, "Back from sleep\n");		if (signal_pending (current)) {			func_exit ();			/* XXX Dec Use count????? */			return -EINTR;		}	}	if (!(port->flags & USSP_DEAMON_PRESENT)) {		ussp_dprintk(DEBUG_OPEN, "Daemon disappeared.\n");		return -EINTR;	}	copy_from_circular_buffer (port->tty_buffer, PAGE_SIZE,				   &port->tty_head, &port->tty_tail,				   &op, sizeof (op), 0);	if ((op.op == USSP_OPEN_RESULT) && (op.arg < 0)) {		ussp_dprintk(DEBUG_OPEN, "Daemon returned error.\n");		return -EINTR;	}	ussp_dprintk (DEBUG_OPEN, "current->signal->leader: %d current->signal->tty: %d tty->session: %d\n", (int)current->signal->leader, (int)current->signal->tty, (int)tty->session);	if (current->signal->leader && !current->signal->tty && tty->session == 0){		ussp_dprintk (DEBUG_OPEN, "setting!\n");		current->signal->tty = tty;		current->signal->tty_old_pgrp = 0;		tty->session = current->signal->session;		tty->pgrp = process_group(current);	}	func_exit();	return op.arg;}static void ussp_tty_close (struct tty_struct *tty, struct file * filep){	struct ussp_port *port = tty->driver_data;	struct ussp_operation op;	func_enter();	ussp_dprintk(DEBUG_CLOSE, "Port: %p\n", port);	if (port) {		port->nusers--;		if (port->nusers < 0) {			printk (KERN_WARNING "Aaargh, nusers count has been corrupted: %d.\n", port->nusers);			port->nusers = 0;		}		if (port->nusers == 0){			op.op = USSP_CLOSE;			op.len = 0;			op.arg = 0;	                ussp_dprintk (DEBUG_CLOSE, "Sending close packet to daemon\n");			if (port->flags & USSP_DEAMON_PRESENT)				copy_to_circular_buffer(port->daemon_buffer, PAGE_SIZE,							&port->daemon_head, &port->daemon_tail,							&op, sizeof (op), 0);			wake_up_interruptible (&port->daemon_wait);			port->tty = NULL;		}	}//	MOD_DEC_USE_COUNT;	func_exit();}static int ussp_tty_ioctl (struct tty_struct * tty, struct file * filp,                           unsigned int cmd, unsigned long arg){	struct ussp_operation op;	struct ussp_port *port;	int rc;	int ival;	func_enter();	port = tty->driver_data;	if (!(port->flags & USSP_DEAMON_PRESENT)) {		ussp_dprintk(DEBUG_IOCTL, "no daemon. Flags: %x\n",			     port->flags);		func_exit ();		return -ENODEV;	}	ussp_dprintk (DEBUG_IOCTL, "IOCTL %x: %lx\n", cmd, arg);	rc = 0;	switch (cmd ){	case TIOCGSOFTCAR:		rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),		              (unsigned int *) arg);		break;	case TCGETA:	case TCGETS:		ussp_dprintk (DEBUG_IOCTL, "TCGETS\n");		rc = n_tty_ioctl (tty, (struct file *) filp, cmd, (unsigned long) arg);		ussp_dprintk (DEBUG_IOCTL, "Returning: %d\n", rc);		break;	case TIOCSSOFTCAR:		if ((rc = verify_area(VERIFY_READ, (void *) arg,		                      sizeof(int))) == 0) {			get_user(ival, (unsigned int *) arg);			tty->termios->c_cflag =				(tty->termios->c_cflag & ~CLOCAL) |				(ival ? CLOCAL : 0);		}		break;	case TIOCMGET:		ussp_dprintk (DEBUG_IOCTL, "TIOCMGET\n");		if (copy_to_user ((unsigned int *)arg, &port->line_status, sizeof(int)))			rc = -EFAULT;		break;	case TIOCMSET:		ussp_dprintk (DEBUG_IOCTL, "TIOCMSET\n");		if (__get_user(port->line_status, (int *)arg))		  rc = -EFAULT;		op.op = USSP_MSC;		op.len = 0;		op.arg = port->line_status;		if (port->flags & USSP_DEAMON_PRESENT)		  copy_to_circular_buffer(port->daemon_buffer, PAGE_SIZE,					  &port->daemon_head,					  &port->daemon_tail,&op,					  sizeof (op), 0);		wake_up_interruptible (&port->daemon_wait);		break;	case TIOSTATGET:		ussp_dprintk (DEBUG_IOCTL, "TIOSTATGET\n");		if (copy_to_user ((struct stats *)arg, &port->stats, sizeof(struct stats)))			rc = -EFAULT;		break;	case FIONREAD:		ussp_dprintk (DEBUG_IOCTL, "FIONREAD\n");		ival = PAGE_SIZE - ((port->daemon_head - port->daemon_tail) & (PAGE_SIZE-1)) - 1;		if (copy_to_user (tty->driver_data, &ival, sizeof(int)))			rc = -EFAULT;		break;	default:		printk (KERN_DEBUG "illegal ioctl: %x (mget = %x)\n",			cmd, TIOCMGET);		rc = -ENOIOCTLCMD;	}	func_exit();	return rc;}static int ussp_tty_write_room(struct tty_struct * tty){	struct ussp_port *port = tty->driver_data;	int ret;	func_enter ();	ret = PAGE_SIZE - ((port->daemon_head - port->daemon_tail) & (PAGE_SIZE-1)) - 1;	ussp_dprintk (DEBUG_CIB, "Free size: %d head: %d tail: %d\n", ret, port->daemon_head,  port->daemon_tail);	if (ret < 0){		ret = 0;		printk(KERN_ERR "Something is very wrong here\n");	}	func_exit ();	ret /= 1 + sizeof (struct ussp_operation);	return ret;}static int ussp_ctl_open(struct inode *inode, struct file *filp){	func_enter();//	MOD_INC_USE_COUNT;	filp->private_data = NULL;	func_exit();	return 0;}static int ussp_ctl_ioctl (struct inode *inode, struct file *filp,                           unsigned int cmd, unsigned long arg){	struct ussp_port *port;	unsigned long flags;	func_enter();	port = filp->private_data;	ussp_dprintk (DEBUG_IOCTL, "CTL_IOCTL %x: %lx\n", cmd, arg);	switch (cmd ) {	case USSP_SET_PORT:		ussp_dprintk (DEBUG_IOCTL, "USSP_SET_PORT\n");		if (port) {			port->flags &= ~USSP_DEAMON_PRESENT;			if (port->daemon_buffer)				free_page ((long) port->daemon_buffer);			if (port->tty_buffer)				free_page ((long) port->tty_buffer);			port->daemon_buffer =				port->tty_buffer = NULL;			filp->private_data = NULL;		}		if ((arg < 0) || ((int)arg > ussp_nports)) {			ussp_dprintk (DEBUG_IOCTL, "invalid arg: %d\n", (int)arg);			func_exit ();			return -EINVAL;		}		ussp_dprintk (DEBUG_IOCTL, "arg: %d\n", (int)arg);		port =  &ussp_ports[(int)arg];		local_irq_save(flags);		if (port->flags & USSP_DEAMON_PRESENT) {			return -EBUSY;		}		port->flags |= USSP_DEAMON_PRESENT;		local_irq_restore(flags);		filp->private_data = port;		init_waitqueue_head (&port->daemon_wait);		init_waitqueue_head (&port->tty_wait);		port->nusers = 0;		port->daemon_head = port->daemon_tail = port->tty_head = port->tty_tail = 0;		port->tty_buffer = (char*)get_zeroed_page(GFP_KERNEL);		port->daemon_buffer = (char*)get_zeroed_page(GFP_KERNEL);		ussp_dprintk(DEBUG_IOCTL, "Got pages: %p, %p\n",port->daemon_buffer,  port->tty_buffer);		port->line_status = 0;		port-> deamon_pid = current->pid;		break;	case USSP_SET_PORT_WATCHER:		if ((arg < 0) || ((int)arg > ussp_nports)) {			ussp_dprintk (DEBUG_IOCTL, "invalid arg: %d\n", (int)arg);			func_exit ();			return -EINVAL;		}		ussp_dprintk (DEBUG_IOCTL, "arg: %d\n", (int)arg);		filp->private_data =  &ussp_ports[(int)arg];		break;	case TIOSTATGET:		ussp_dprintk (DEBUG_IOCTL, "TIOSTATGET\n");		if (!port || copy_to_user ((struct stats *)arg, &port->stats, sizeof(struct stats))) {			func_exit ();			return -EFAULT;		}		break;	case TIOCMGET:		ussp_dprintk (DEBUG_IOCTL, "TIOCMGET\n");		if (copy_to_user ((unsigned int *)arg, &port->line_status, sizeof(int))) {			func_exit ();			return -EFAULT;		}		break;	default:		printk ("illegal ioctl: %x\n", cmd);	}	func_exit();	return 0;}static ssize_t ussp_ctl_read(struct file * filp, char * buf,   			     size_t count, loff_t *ppos){	struct ussp_port *port;	func_enter();	if (!filp){		func_exit ();		return -EINVAL;	}	port = filp->private_data;	if (!port) {		func_exit ();		return -EINVAL;	}	ussp_dprintk (DEBUG_READ_CTL, "Checking data available: %ld\n", D_DATA_AVAILABLE(port));	while (!D_DATA_AVAILABLE(port)) {		interruptible_sleep_on (&port->daemon_wait);		if (signal_pending (current)) {			func_exit ();			return -EINTR;		}	}	if (count > D_DATA_AVAILABLE (port))		count = D_DATA_AVAILABLE (port);	if (copy_from_circular_buffer (port->daemon_buffer, PAGE_SIZE,				       &port->daemon_head, &port->daemon_tail,				       buf, count, 1)){		printk("Error copying to the daemon\n");		func_exit ();		return -EFAULT;	}	if (port->tty) {		if ((port->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&		    (port->tty->ldisc.write_wakeup) &&		    (D_DATA_AVAILABLE(port) < (PAGE_SIZE/4)))			port->tty->ldisc.write_wakeup(port->tty);		ussp_dprintk (DEBUG_READ_CTL, "Waking up write_wait\n");		wake_up_interruptible(&port->tty->write_wait);	}	func_exit ();	return count;}static ssize_t ussp_ctl_write(struct file * filp, const char * buf,	  		      size_t count, loff_t *ppos){	int rc;	struct ussp_operation op;	struct ussp_port *port;	func_enter();	port = filp->private_data;	if (count <= 0){		ussp_dprintk (DEBUG_WRITE_TO_CTL, "Count is smaller then 0!\n");		func_exit ();		return 0;	}	if (!filp->private_data){		func_exit ();		return -EINVAL;	}	if (!port->tty_buffer)		ussp_dprintk (DEBUG_WRITE_TO_CTL, "ERROR!! port->tty_buffer is NULL!!!\n");	if (!port->tty){		ussp_dprintk (DEBUG_WRITE_TO_CTL, "ERROR!! port->tty is NULL !!!!!!\n");		func_exit ();		return -EINVAL;	}	rc = copy_from_user (&op, buf, sizeof (op));	switch(op.op) {	case USSP_OPEN_RESULT:		ussp_dprintk (DEBUG_OPEN, "USSP_OPEN_RESULT %d\n", (int)op.arg);		copy_to_circular_buffer (port->tty_buffer, PAGE_SIZE,					 &port->tty_head, &port->tty_tail,					 buf, sizeof (op), 1);		wake_up_interruptible (&port->tty_wait);		break;	case USSP_READ:		ussp_dprintk (DEBUG_IOCTL, "USSP_READ %d\n", (int)op.len);		rc = copy_from_user (port->tty->flip.char_buf_ptr, buf + sizeof(struct ussp_operation), op.len);		memset(port->tty->flip.flag_buf_ptr, TTY_NORMAL, op.len);		port->tty->flip.count += op.len;		port->tty->flip.char_buf_ptr += op.len;		port->tty->flip.flag_buf_ptr += op.len;		tty_flip_buffer_push (port->tty);		port->stats.rxcount += op.len;		break;	case USSP_FORCE_CLOSE:		ussp_dprintk (USSP_CLOSE, "USSP_FORCE_CLOSE %d\n", (int)op.arg);		tty_hangup (port->tty);		port->tty = NULL;		break;	case USSP_MSC:		ussp_dprintk (DEBUG_INFO, "USSP_MSC packet: %x %x\n", (int)op.arg, (int)port->line_status);		if ((port->line_status & USSP_DCD) && (!(op.arg & USSP_DCD))) {			ussp_dprintk (DEBUG_IOCTL, "Obliged to perform hangup... \n");			/* tty_hangup (port->tty); */		}		port->line_status = op.arg;		break;	};	func_exit();	return 0;}static int ussp_ctl_close(struct inode *inodes, struct file * filp){	struct ussp_port *port;	func_enter ();	ussp_dprintk(DEBUG_CLOSE, "filp: %p\n", filp);	if (filp) {		port = filp->private_data;		if (port && (current ->pid == port->deamon_pid)) {			if (port->tty) {				ussp_dprintk (DEBUG_CLOSE, "Hanging up: %p\n", port);				/* Make sure the tty sides of this gets shutdown properly... */				tty_hangup (port->tty);				port->tty = NULL;			}			ussp_dprintk(DEBUG_CLOSE, "Freeing pages: %p, %p\n", port->daemon_buffer,  port->tty_buffer);			if (port->daemon_buffer)				free_page ((long)port->daemon_buffer);			if (port->tty_buffer)				free_page ((long)port->tty_buffer);			port->daemon_buffer = port->tty_buffer = NULL;			ussp_dprintk(DEBUG_CLOSE, "Removing flag\n");			port->flags &= ~USSP_DEAMON_PRESENT;			wake_up_interruptible (&port->tty_wait);		} else {			/* This deamon must've been unattached... */			ussp_dprintk(DEBUG_CLOSE, "close: NULL Port!\n");		}	}//	MOD_DEC_USE_COUNT;	func_exit();	return 0;}static unsigned int ussp_ctl_poll (struct file *filep, poll_table * wait){	struct ussp_port *port;	int mask;	func_enter();	port = filep->private_data;	if (port) {		ussp_dprintk(DEBUG_BUFFERS, "Before poll_wait port: %p,head: %d, tail: %d, port:%x, psz:%x, ports:%x\n",		       port, port->daemon_head, port->daemon_tail, (int)port, sizeof(*port), (int)ussp_ports);		poll_wait (filep, &port->daemon_wait, wait);		mask = 0;		if(port->daemon_head != port->daemon_tail)			mask |= POLLIN | POLLRDNORM;		ussp_dprintk(DEBUG_BUFFERS, "After poll_wait port: %p,head: %d, tail: %d, mask=%x\n",		       port, port->daemon_head, port->daemon_tail, mask);	} else		mask = -ENODEV;	func_exit();	return mask;}static int ussp_tty_chars_in_buffer (struct tty_struct *tty){	struct ussp_port *port;	int rv;	func_enter ();	port = tty->driver_data;	rv = (port->daemon_head - port->daemon_tail) & (PAGE_SIZE -1);	ussp_dprintk(DEBUG_CIB, "Chars in buffer %d\n", rv);	func_exit ();	return rv;}int __init init_ussp_module(void){	int status;	func_enter();	status = ussp_init();	func_exit();	return status;}void __exit exit_ussp_module(void){	func_enter();	if (misc_deregister(&ussp_ctl_device) < 0) {		printk (KERN_INFO "ussp: couldn't deregister control device.\n");	}	if (tty_unregister_driver(&ussp_driver) < 0) {		printk (KERN_INFO "ussp:  couldn't deregister tty device.\n");	}	func_exit();}module_init(init_ussp_module);module_exit(exit_ussp_module);//EXPORT_NO_SYMBOLS;

⌨️ 快捷键说明

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