📄 digi_acceleport.c
字号:
unsigned long flags = 0; dbg("digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count); /* if disconnected, just clear flags */ if (!usb_get_intfdata(port->serial->interface)) goto exit; /* do cleanup only after final close on this port */ spin_lock_irqsave(&priv->dp_port_lock, flags); priv->dp_in_close = 1; spin_unlock_irqrestore(&priv->dp_port_lock, flags); /* tell line discipline to process only XON/XOFF */ tty->closing = 1; /* wait for output to drain */ if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT); /* flush driver and line discipline buffers */ if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); if (port->serial->dev) { /* wait for transmit idle */ if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) { digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); } /* drop DTR and RTS */ digi_set_modem_signals(port, 0, 0); /* disable input flow control */ buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; buf[1] = priv->dp_port_num; buf[2] = DIGI_DISABLE; buf[3] = 0; /* disable output flow control */ buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; buf[5] = priv->dp_port_num; buf[6] = DIGI_DISABLE; buf[7] = 0; /* disable reading modem signals automatically */ buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; buf[9] = priv->dp_port_num; buf[10] = DIGI_DISABLE; buf[11] = 0; /* disable receive */ buf[12] = DIGI_CMD_RECEIVE_ENABLE; buf[13] = priv->dp_port_num; buf[14] = DIGI_DISABLE; buf[15] = 0; /* flush fifos */ buf[16] = DIGI_CMD_IFLUSH_FIFO; buf[17] = priv->dp_port_num; buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; buf[19] = 0; if ((ret = digi_write_oob_command(port, buf, 20, 0)) != 0) dbg("digi_close: write oob failed, ret=%d", ret); /* wait for final commands on oob port to complete */ prepare_to_wait(&priv->dp_flush_wait, &wait, TASK_INTERRUPTIBLE); schedule_timeout(DIGI_CLOSE_TIMEOUT); finish_wait(&priv->dp_flush_wait, &wait); /* shutdown any outstanding bulk writes */ usb_kill_urb(port->write_urb); } tty->closing = 0;exit: spin_lock_irqsave(&priv->dp_port_lock, flags); priv->dp_write_urb_in_use = 0; priv->dp_in_close = 0; wake_up_interruptible(&priv->dp_close_wait); spin_unlock_irqrestore(&priv->dp_port_lock, flags); dbg("digi_close: done");}/** Digi Startup Device** Starts reads on all ports. Must be called AFTER startup, with* urbs initialized. Returns 0 if successful, non-zero error otherwise.*/static int digi_startup_device(struct usb_serial *serial){ int i,ret = 0; struct digi_serial *serial_priv = usb_get_serial_data(serial); struct usb_serial_port *port; /* be sure this happens exactly once */ spin_lock(&serial_priv->ds_serial_lock); if (serial_priv->ds_device_started) { spin_unlock(&serial_priv->ds_serial_lock); return 0; } serial_priv->ds_device_started = 1; spin_unlock(&serial_priv->ds_serial_lock); /* start reading from each bulk in endpoint for the device */ /* set USB_DISABLE_SPD flag for write bulk urbs */ for (i = 0; i < serial->type->num_ports + 1; i++) { port = serial->port[i]; port->write_urb->dev = port->serial->dev; if ((ret = usb_submit_urb(port->read_urb, GFP_KERNEL)) != 0) { err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__, ret, i); break; } } return ret;}static int digi_startup(struct usb_serial *serial){ int i; struct digi_port *priv; struct digi_serial *serial_priv; dbg("digi_startup: TOP"); /* allocate the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ for(i = 0; i < serial->type->num_ports + 1; i++) { /* allocate port private structure */ priv = kmalloc(sizeof(struct digi_port), GFP_KERNEL); if (priv == NULL) { while (--i >= 0) kfree(usb_get_serial_port_data(serial->port[i])); return 1; /* error */ } /* initialize port private structure */ spin_lock_init(&priv->dp_port_lock); priv->dp_port_num = i; priv->dp_out_buf_len = 0; priv->dp_write_urb_in_use = 0; priv->dp_modem_signals = 0; init_waitqueue_head(&priv->dp_modem_change_wait); priv->dp_transmit_idle = 0; init_waitqueue_head(&priv->dp_transmit_idle_wait); priv->dp_throttled = 0; priv->dp_throttle_restart = 0; init_waitqueue_head(&priv->dp_flush_wait); priv->dp_in_close = 0; init_waitqueue_head(&priv->dp_close_wait); INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); priv->dp_port = serial->port[i]; /* initialize write wait queue for this port */ init_waitqueue_head(&serial->port[i]->write_wait); usb_set_serial_port_data(serial->port[i], priv); } /* allocate serial private structure */ serial_priv = kmalloc(sizeof(struct digi_serial), GFP_KERNEL); if (serial_priv == NULL) { for (i = 0; i < serial->type->num_ports + 1; i++) kfree(usb_get_serial_port_data(serial->port[i])); return 1; /* error */ } /* initialize serial private structure */ spin_lock_init(&serial_priv->ds_serial_lock); serial_priv->ds_oob_port_num = serial->type->num_ports; serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num]; serial_priv->ds_device_started = 0; usb_set_serial_data(serial, serial_priv); return 0;}static void digi_shutdown(struct usb_serial *serial){ int i; dbg("digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt()); /* stop reads and writes on all ports */ for (i = 0; i < serial->type->num_ports + 1; i++) { usb_kill_urb(serial->port[i]->read_urb); usb_kill_urb(serial->port[i]->write_urb); } /* free the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ for(i = 0; i < serial->type->num_ports + 1; i++) kfree(usb_get_serial_port_data(serial->port[i])); kfree(usb_get_serial_data(serial));}static void digi_read_bulk_callback(struct urb *urb){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct digi_port *priv; struct digi_serial *serial_priv; int ret; int status = urb->status; dbg("digi_read_bulk_callback: TOP"); /* port sanity check, do not resubmit if port is not valid */ if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { err("%s: port or port->private is NULL, status=%d", __FUNCTION__, status); return; } if (port->serial == NULL || (serial_priv=usb_get_serial_data(port->serial)) == NULL) { err("%s: serial is bad or serial->private is NULL, status=%d", __FUNCTION__, status); return; } /* do not resubmit urb if it has any status error */ if (status) { err("%s: nonzero read bulk status: status=%d, port=%d", __FUNCTION__, status, priv->dp_port_num); return; } /* handle oob or inb callback, do not resubmit if error */ if (priv->dp_port_num == serial_priv->ds_oob_port_num) { if (digi_read_oob_callback(urb) != 0) return; } else { if (digi_read_inb_callback(urb) != 0) return; } /* continue read */ urb->dev = port->serial->dev; if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { err("%s: failed resubmitting urb, ret=%d, port=%d", __FUNCTION__, ret, priv->dp_port_num); }}/* * Digi Read INB Callback** Digi Read INB Callback handles reads on the in band ports, sending* the data on to the tty subsystem. When called we know port and* port->private are not NULL and port->serial has been validated.* It returns 0 if successful, 1 if successful but the port is* throttled, and -1 if the sanity checks failed.*/static int digi_read_inb_callback(struct urb *urb){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct tty_struct *tty = port->tty; struct digi_port *priv = usb_get_serial_port_data(port); int opcode = ((unsigned char *)urb->transfer_buffer)[0]; int len = ((unsigned char *)urb->transfer_buffer)[1]; int port_status = ((unsigned char *)urb->transfer_buffer)[2]; unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3; int flag,throttled; int i; int status = urb->status; /* do not process callbacks on closed ports */ /* but do continue the read chain */ if (port->open_count == 0) return 0; /* short/multiple packet check */ if (urb->actual_length != len + 2) { err("%s: INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, " "port=%d, opcode=%d, len=%d, actual_length=%d, " "status=%d", __FUNCTION__, status, priv->dp_port_num, opcode, len, urb->actual_length, port_status); return -1; } spin_lock(&priv->dp_port_lock); /* check for throttle; if set, do not resubmit read urb */ /* indicate the read chain needs to be restarted on unthrottle */ throttled = priv->dp_throttled; if (throttled) priv->dp_throttle_restart = 1; /* receive data */ if (opcode == DIGI_CMD_RECEIVE_DATA) { /* get flag from port_status */ flag = 0; /* overrun is special, not associated with a char */ if (port_status & DIGI_OVERRUN_ERROR) tty_insert_flip_char(tty, 0, TTY_OVERRUN); /* break takes precedence over parity, */ /* which takes precedence over framing errors */ if (port_status & DIGI_BREAK_ERROR) flag = TTY_BREAK; else if (port_status & DIGI_PARITY_ERROR) flag = TTY_PARITY; else if (port_status & DIGI_FRAMING_ERROR) flag = TTY_FRAME; /* data length is len-1 (one byte of len is port_status) */ --len; len = tty_buffer_request_room(tty, len); if (len > 0) { /* Hot path */ if (flag == TTY_NORMAL) tty_insert_flip_string(tty, data, len); else { for(i = 0; i < len; i++) tty_insert_flip_char(tty, data[i], flag); } tty_flip_buffer_push(tty); } } spin_unlock(&priv->dp_port_lock); if (opcode == DIGI_CMD_RECEIVE_DISABLE) dbg("%s: got RECEIVE_DISABLE", __FUNCTION__); else if (opcode != DIGI_CMD_RECEIVE_DATA) dbg("%s: unknown opcode: %d", __FUNCTION__, opcode); return(throttled ? 1 : 0);}/* * Digi Read OOB Callback** Digi Read OOB Callback handles reads on the out of band port.* When called we know port and port->private are not NULL and* the port->serial is valid. It returns 0 if successful, and* -1 if the sanity checks failed.*/static int digi_read_oob_callback(struct urb *urb){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; struct digi_port *priv = usb_get_serial_port_data(port); int opcode, line, status, val; int i; dbg("digi_read_oob_callback: port=%d, len=%d", priv->dp_port_num, urb->actual_length); /* handle each oob command */ for(i = 0; i < urb->actual_length - 3;) { opcode = ((unsigned char *)urb->transfer_buffer)[i++]; line = ((unsigned char *)urb->transfer_buffer)[i++]; status = ((unsigned char *)urb->transfer_buffer)[i++]; val = ((unsigned char *)urb->transfer_buffer)[i++]; dbg("digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, line, status, val); if (status != 0 || line >= serial->type->num_ports) continue; port = serial->port[line]; if ((priv=usb_get_serial_port_data(port)) == NULL) return -1; if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) { spin_lock(&priv->dp_port_lock); /* convert from digi flags to termiox flags */ if (val & DIGI_READ_INPUT_SIGNALS_CTS) { priv->dp_modem_signals |= TIOCM_CTS; /* port must be open to use tty struct */ if (port->open_count && port->tty->termios->c_cflag & CRTSCTS) { port->tty->hw_stopped = 0; digi_wakeup_write(port); } } else { priv->dp_modem_signals &= ~TIOCM_CTS; /* port must be open to use tty struct */ if (port->open_count && port->tty->termios->c_cflag & CRTSCTS) { port->tty->hw_stopped = 1; } } if (val & DIGI_READ_INPUT_SIGNALS_DSR) priv->dp_modem_signals |= TIOCM_DSR; else priv->dp_modem_signals &= ~TIOCM_DSR; if (val & DIGI_READ_INPUT_SIGNALS_RI) priv->dp_modem_signals |= TIOCM_RI; else priv->dp_modem_signals &= ~TIOCM_RI; if (val & DIGI_READ_INPUT_SIGNALS_DCD) priv->dp_modem_signals |= TIOCM_CD; else priv->dp_modem_signals &= ~TIOCM_CD; wake_up_interruptible(&priv->dp_modem_change_wait); spin_unlock(&priv->dp_port_lock); } else if (opcode == DIGI_CMD_TRANSMIT_IDLE) { spin_lock(&priv->dp_port_lock); priv->dp_transmit_idle = 1; wake_up_interruptible(&priv->dp_transmit_idle_wait); spin_unlock(&priv->dp_port_lock); } else if (opcode == DIGI_CMD_IFLUSH_FIFO) { wake_up_interruptible(&priv->dp_flush_wait); } } return 0;}static int __init digi_init(void){ int retval; retval = usb_serial_register(&digi_acceleport_2_device); if (retval) goto failed_acceleport_2_device; retval = usb_serial_register(&digi_acceleport_4_device); if (retval) goto failed_acceleport_4_device; retval = usb_register(&digi_driver); if (retval) goto failed_usb_register; info(DRIVER_VERSION ":" DRIVER_DESC); return 0;failed_usb_register: usb_serial_deregister(&digi_acceleport_4_device);failed_acceleport_4_device: usb_serial_deregister(&digi_acceleport_2_device);failed_acceleport_2_device: return retval;}static void __exit digi_exit (void){ usb_deregister(&digi_driver); usb_serial_deregister(&digi_acceleport_2_device); usb_serial_deregister(&digi_acceleport_4_device);}module_init(digi_init);module_exit(digi_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");module_param(debug, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Debug enabled or not");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -