📄 whiteheat.c
字号:
dbg("%s - bad reply from firmware", __FUNCTION__); } /* Continue trying to always read */ command_port->read_urb->dev = command_port->serial->dev; result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC); spin_unlock_irqrestore(&command_info->lock, flags); if (result) dbg("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);}static void whiteheat_read_callback(struct urb *urb, struct pt_regs *regs){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct whiteheat_urb_wrap *wrap; unsigned char *data = urb->transfer_buffer; struct whiteheat_private *info = usb_get_serial_port_data(port); dbg("%s - port %d", __FUNCTION__, port->number); spin_lock(&info->lock); wrap = urb_to_wrap(urb, &info->rx_urbs_submitted); if (!wrap) { spin_unlock(&info->lock); err("%s - Not my urb!", __FUNCTION__); return; } list_del(&wrap->list); spin_unlock(&info->lock); if (urb->status) { dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); spin_lock(&info->lock); list_add(&wrap->list, &info->rx_urbs_free); spin_unlock(&info->lock); return; } usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); spin_lock(&info->lock); list_add_tail(&wrap->list, &info->rx_urb_q); if (info->flags & THROTTLED) { info->flags |= ACTUALLY_THROTTLED; spin_unlock(&info->lock); return; } spin_unlock(&info->lock); schedule_work(&info->rx_work);}static void whiteheat_write_callback(struct urb *urb, struct pt_regs *regs){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct whiteheat_private *info = usb_get_serial_port_data(port); struct whiteheat_urb_wrap *wrap; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock(&info->lock); wrap = urb_to_wrap(urb, &info->tx_urbs_submitted); if (!wrap) { spin_unlock(&info->lock); err("%s - Not my urb!", __FUNCTION__); return; } list_del(&wrap->list); list_add(&wrap->list, &info->tx_urbs_free); spin_unlock(&info->lock); if (urb->status) { dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } usb_serial_port_softint((void *)port); schedule_work(&port->work);}/***************************************************************************** * Connect Tech's White Heat firmware interface *****************************************************************************/static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize){ struct usb_serial_port *command_port; struct whiteheat_command_private *command_info; struct whiteheat_private *info; __u8 *transfer_buffer; int retval = 0; unsigned long flags; dbg("%s - command %d", __FUNCTION__, command); command_port = port->serial->port[COMMAND_PORT]; command_info = usb_get_serial_port_data(command_port); spin_lock_irqsave(&command_info->lock, flags); command_info->command_finished = FALSE; transfer_buffer = (__u8 *)command_port->write_urb->transfer_buffer; transfer_buffer[0] = command; memcpy (&transfer_buffer[1], data, datasize); command_port->write_urb->transfer_buffer_length = datasize + 1; command_port->write_urb->dev = port->serial->dev; retval = usb_submit_urb (command_port->write_urb, GFP_KERNEL); if (retval) { dbg("%s - submit urb failed", __FUNCTION__); goto exit; } spin_unlock_irqrestore(&command_info->lock, flags); /* wait for the command to complete */ wait_event_interruptible_timeout(command_info->wait_command, (command_info->command_finished != FALSE), COMMAND_TIMEOUT); spin_lock_irqsave(&command_info->lock, flags); if (command_info->command_finished == FALSE) { dbg("%s - command timed out.", __FUNCTION__); retval = -ETIMEDOUT; goto exit; } if (command_info->command_finished == WHITEHEAT_CMD_FAILURE) { dbg("%s - command failed.", __FUNCTION__); retval = -EIO; goto exit; } if (command_info->command_finished == WHITEHEAT_CMD_COMPLETE) { dbg("%s - command completed.", __FUNCTION__); switch (command) { case WHITEHEAT_GET_DTR_RTS: info = usb_get_serial_port_data(port); memcpy(&info->mcr, command_info->result_buffer, sizeof(struct whiteheat_dr_info)); break; } }exit: spin_unlock_irqrestore(&command_info->lock, flags); return retval;}static int firm_open(struct usb_serial_port *port) { struct whiteheat_simple open_command; open_command.port = port->number - port->serial->minor + 1; return firm_send_command(port, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));}static int firm_close(struct usb_serial_port *port) { struct whiteheat_simple close_command; close_command.port = port->number - port->serial->minor + 1; return firm_send_command(port, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));}static int firm_setup_port(struct usb_serial_port *port) { struct whiteheat_port_settings port_settings; unsigned int cflag = port->tty->termios->c_cflag; port_settings.port = port->number + 1; /* get the byte size */ switch (cflag & CSIZE) { case CS5: port_settings.bits = 5; break; case CS6: port_settings.bits = 6; break; case CS7: port_settings.bits = 7; break; default: case CS8: port_settings.bits = 8; break; } dbg("%s - data bits = %d", __FUNCTION__, port_settings.bits); /* determine the parity */ if (cflag & PARENB) if (cflag & CMSPAR) if (cflag & PARODD) port_settings.parity = WHITEHEAT_PAR_MARK; else port_settings.parity = WHITEHEAT_PAR_SPACE; else if (cflag & PARODD) port_settings.parity = WHITEHEAT_PAR_ODD; else port_settings.parity = WHITEHEAT_PAR_EVEN; else port_settings.parity = WHITEHEAT_PAR_NONE; dbg("%s - parity = %c", __FUNCTION__, port_settings.parity); /* figure out the stop bits requested */ if (cflag & CSTOPB) port_settings.stop = 2; else port_settings.stop = 1; dbg("%s - stop bits = %d", __FUNCTION__, port_settings.stop); /* figure out the flow control settings */ if (cflag & CRTSCTS) port_settings.hflow = (WHITEHEAT_HFLOW_CTS | WHITEHEAT_HFLOW_RTS); else port_settings.hflow = WHITEHEAT_HFLOW_NONE; dbg("%s - hardware flow control = %s %s %s %s", __FUNCTION__, (port_settings.hflow & WHITEHEAT_HFLOW_CTS) ? "CTS" : "", (port_settings.hflow & WHITEHEAT_HFLOW_RTS) ? "RTS" : "", (port_settings.hflow & WHITEHEAT_HFLOW_DSR) ? "DSR" : "", (port_settings.hflow & WHITEHEAT_HFLOW_DTR) ? "DTR" : ""); /* determine software flow control */ if (I_IXOFF(port->tty)) port_settings.sflow = WHITEHEAT_SFLOW_RXTX; else port_settings.sflow = WHITEHEAT_SFLOW_NONE; dbg("%s - software flow control = %c", __FUNCTION__, port_settings.sflow); port_settings.xon = START_CHAR(port->tty); port_settings.xoff = STOP_CHAR(port->tty); dbg("%s - XON = %2x, XOFF = %2x", __FUNCTION__, port_settings.xon, port_settings.xoff); /* get the baud rate wanted */ port_settings.baud = tty_get_baud_rate(port->tty); dbg("%s - baud rate = %d", __FUNCTION__, port_settings.baud); /* handle any settings that aren't specified in the tty structure */ port_settings.lloop = 0; /* now send the message to the device */ return firm_send_command(port, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings));}static int firm_set_rts(struct usb_serial_port *port, __u8 onoff) { struct whiteheat_set_rdb rts_command; rts_command.port = port->number - port->serial->minor + 1; rts_command.state = onoff; return firm_send_command(port, WHITEHEAT_SET_RTS, (__u8 *)&rts_command, sizeof(rts_command));}static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff) { struct whiteheat_set_rdb dtr_command; dtr_command.port = port->number - port->serial->minor + 1; dtr_command.state = onoff; return firm_send_command(port, WHITEHEAT_SET_RTS, (__u8 *)&dtr_command, sizeof(dtr_command));}static int firm_set_break(struct usb_serial_port *port, __u8 onoff) { struct whiteheat_set_rdb break_command; break_command.port = port->number - port->serial->minor + 1; break_command.state = onoff; return firm_send_command(port, WHITEHEAT_SET_RTS, (__u8 *)&break_command, sizeof(break_command));}static int firm_purge(struct usb_serial_port *port, __u8 rxtx) { struct whiteheat_purge purge_command; purge_command.port = port->number - port->serial->minor + 1; purge_command.what = rxtx; return firm_send_command(port, WHITEHEAT_PURGE, (__u8 *)&purge_command, sizeof(purge_command));}static int firm_get_dtr_rts(struct usb_serial_port *port) { struct whiteheat_simple get_dr_command; get_dr_command.port = port->number - port->serial->minor + 1; return firm_send_command(port, WHITEHEAT_GET_DTR_RTS, (__u8 *)&get_dr_command, sizeof(get_dr_command));}static int firm_report_tx_done(struct usb_serial_port *port) { struct whiteheat_simple close_command; close_command.port = port->number - port->serial->minor + 1; return firm_send_command(port, WHITEHEAT_REPORT_TX_DONE, (__u8 *)&close_command, sizeof(close_command));}/***************************************************************************** * Connect Tech's White Heat utility functions *****************************************************************************/static int start_command_port(struct usb_serial *serial){ struct usb_serial_port *command_port; struct whiteheat_command_private *command_info; unsigned long flags; int retval = 0; command_port = serial->port[COMMAND_PORT]; command_info = usb_get_serial_port_data(command_port); spin_lock_irqsave(&command_info->lock, flags); if (!command_info->port_running) { /* Work around HCD bugs */ usb_clear_halt(serial->dev, command_port->read_urb->pipe); command_port->read_urb->dev = serial->dev; retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL); if (retval) { err("%s - failed submitting read urb, error %d", __FUNCTION__, retval); goto exit; } } command_info->port_running++;exit: spin_unlock_irqrestore(&command_info->lock, flags); return retval;}static void stop_command_port(struct usb_serial *serial){ struct usb_serial_port *command_port; struct whiteheat_command_private *command_info; unsigned long flags; command_port = serial->port[COMMAND_PORT]; command_info = usb_get_serial_port_data(command_port); spin_lock_irqsave(&command_info->lock, flags); command_info->port_running--; if (!command_info->port_running) usb_kill_urb(command_port->read_urb); spin_unlock_irqrestore(&command_info->lock, flags);}static int start_port_read(struct usb_serial_port *port){ struct whiteheat_private *info = usb_get_serial_port_data(port); struct whiteheat_urb_wrap *wrap; struct urb *urb; int retval = 0; unsigned long flags; struct list_head *tmp; struct list_head *tmp2; spin_lock_irqsave(&info->lock, flags); list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { list_del(tmp); wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); urb = wrap->urb; urb->dev = port->serial->dev; retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { list_add(tmp, &info->rx_urbs_free); list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); urb = wrap->urb; usb_kill_urb(urb); list_del(tmp); list_add(tmp, &info->rx_urbs_free); } break; } list_add(tmp, &info->rx_urbs_submitted); } spin_unlock_irqrestore(&info->lock, flags); return retval;}static struct whiteheat_urb_wrap *urb_to_wrap(struct urb* urb, struct list_head *head){ struct whiteheat_urb_wrap *wrap; struct list_head *tmp; list_for_each(tmp, head) { wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); if (wrap->urb == urb) return wrap; } return NULL;}static struct list_head *list_first(struct list_head *head){ return head->next;}static void rx_data_softint(void *private){ struct usb_serial_port *port = (struct usb_serial_port *)private; struct whiteheat_private *info = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; struct whiteheat_urb_wrap *wrap; struct urb *urb; unsigned long flags; struct list_head *tmp; struct list_head *tmp2; int result; int sent = 0; spin_lock_irqsave(&info->lock, flags); if (info->flags & THROTTLED) { spin_unlock_irqrestore(&info->lock, flags); return; } list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { list_del(tmp); spin_unlock_irqrestore(&info->lock, flags); wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); urb = wrap->urb; if (tty && urb->actual_length) { if (urb->actual_length > TTY_FLIPBUF_SIZE - tty->flip.count) { spin_lock_irqsave(&info->lock, flags); list_add(tmp, &info->rx_urb_q); spin_unlock_irqrestore(&info->lock, flags); tty_flip_buffer_push(tty); schedule_work(&info->rx_work); return; } memcpy(tty->flip.char_buf_ptr, urb->transfer_buffer, urb->actual_length); tty->flip.char_buf_ptr += urb->actual_length; tty->flip.count += urb->actual_length; sent += urb->actual_length; } urb->dev = port->serial->dev; result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); spin_lock_irqsave(&info->lock, flags); list_add(tmp, &info->rx_urbs_free); continue; } spin_lock_irqsave(&info->lock, flags); list_add(tmp, &info->rx_urbs_submitted); } spin_unlock_irqrestore(&info->lock, flags); if (sent) tty_flip_buffer_push(tty);}/***************************************************************************** * Connect Tech's White Heat module functions *****************************************************************************/static int __init whiteheat_init (void){ int retval; retval = usb_serial_register(&whiteheat_fake_device); if (retval) goto failed_fake_register; retval = usb_serial_register(&whiteheat_device); if (retval) goto failed_device_register; retval = usb_register(&whiteheat_driver); if (retval) goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0;failed_usb_register: usb_serial_deregister(&whiteheat_device);failed_device_register: usb_serial_deregister(&whiteheat_fake_device);failed_fake_register: return retval;}static void __exit whiteheat_exit (void){ usb_deregister (&whiteheat_driver); usb_serial_deregister (&whiteheat_fake_device); usb_serial_deregister (&whiteheat_device);}module_init(whiteheat_init);module_exit(whiteheat_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");module_param(urb_pool_size, int, 0);MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering");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 + -