📄 ussp.c
字号:
}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 + -