📄 whiteheat.c
字号:
static void whiteheat_close(struct usb_serial_port *port, struct file * filp){ struct whiteheat_min_set close_command; dbg("%s - port %d", __FUNCTION__, port->number); /* send a close command to the port */ /* firmware uses 1 based port numbering */ close_command.port = port->number - port->serial->minor + 1; whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command)); /* Need to change the control lines here */ /* FIXME */ /* shutdown our bulk reads and writes */ usb_unlink_urb (port->write_urb); usb_unlink_urb (port->read_urb);}static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg){ dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd); return -ENOIOCTLCMD;}static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios){ unsigned int cflag; struct whiteheat_port_settings port_settings; dbg("%s -port %d", __FUNCTION__, port->number); if ((!port->tty) || (!port->tty->termios)) { dbg("%s - no tty structures", __FUNCTION__); goto exit; } cflag = port->tty->termios->c_cflag; /* check that they really want us to change something */ if (old_termios) { if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { dbg("%s - nothing to change...", __FUNCTION__); goto exit; } } /* set the port number */ /* firmware uses 1 based port numbering */ 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 & PARODD) port_settings.parity = 'o'; else port_settings.parity = 'e'; else port_settings.parity = 'n'; 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_CTS_FLOW | WHITEHEAT_RTS_FLOW); else port_settings.hflow = 0; dbg("%s - hardware flow control = %s %s %s %s", __FUNCTION__, (port_settings.hflow & WHITEHEAT_CTS_FLOW) ? "CTS" : "", (port_settings.hflow & WHITEHEAT_RTS_FLOW) ? "RTS" : "", (port_settings.hflow & WHITEHEAT_DSR_FLOW) ? "DSR" : "", (port_settings.hflow & WHITEHEAT_DTR_FLOW) ? "DTR" : ""); /* determine software flow control */ if (I_IXOFF(port->tty)) port_settings.sflow = 'b'; else port_settings.sflow = 'n'; 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 */ whiteheat_send_cmd (port->serial, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings)); exit: return;}static void whiteheat_throttle (struct usb_serial_port *port){ dbg("%s - port %d", __FUNCTION__, port->number); /* Change the control signals */ /* FIXME!!! */ return;}static void whiteheat_unthrottle (struct usb_serial_port *port){ dbg("%s - port %d", __FUNCTION__, port->number); /* Change the control signals */ /* FIXME!!! */ return;}/* steps to download the firmware to the WhiteHEAT device: - hold the reset (by writing to the reset bit of the CPUCS register) - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD - release the reset (by writing to the CPUCS register) - download the WH.HEX file for all addresses greater than 0x1b3f using VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD - hold the reset - download the WH.HEX file for all addresses less than 0x1b40 using VENDOR_REQUEST_ANCHOR_LOAD - release the reset - device renumerated itself and comes up as new device id with all firmware download completed.*/static int whiteheat_fake_startup (struct usb_serial *serial){ int response; const struct whiteheat_hex_record *record; dbg("%s", __FUNCTION__); response = ezusb_set_reset (serial, 1); record = &whiteheat_loader[0]; while (record->address != 0xffff) { response = ezusb_writememory (serial, record->address, (unsigned char *)record->data, record->data_size, 0xa0); if (response < 0) { err("%s - ezusb_writememory failed for loader (%d %04X %p %d)", __FUNCTION__, response, record->address, record->data, record->data_size); break; } ++record; } response = ezusb_set_reset (serial, 0); record = &whiteheat_firmware[0]; while (record->address < 0x1b40) { ++record; } while (record->address != 0xffff) { response = ezusb_writememory (serial, record->address, (unsigned char *)record->data, record->data_size, 0xa3); if (response < 0) { err("%s - ezusb_writememory failed for first firmware step (%d %04X %p %d)", __FUNCTION__, response, record->address, record->data, record->data_size); break; } ++record; } response = ezusb_set_reset (serial, 1); record = &whiteheat_firmware[0]; while (record->address < 0x1b40) { response = ezusb_writememory (serial, record->address, (unsigned char *)record->data, record->data_size, 0xa0); if (response < 0) { err("%s - ezusb_writememory failed for second firmware step (%d %04X %p %d)", __FUNCTION__, response, record->address, record->data, record->data_size); break; } ++record; } response = ezusb_set_reset (serial, 0); /* we want this device to fail to have a driver assigned to it. */ return 1;}static int whiteheat_real_startup (struct usb_serial *serial){ struct whiteheat_hw_info *hw_info; int pipe; int ret; int alen; __u8 command[2] = { WHITEHEAT_GET_HW_INFO, 0 }; __u8 result[sizeof(*hw_info) + 1]; pipe = usb_rcvbulkpipe (serial->dev, 7); usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, 2 * HZ); /* * We ignore the return code. In the case where rmmod/insmod is * performed with a WhiteHEAT connected, the above times out * because the endpoint is already prepped, meaning the below succeeds * regardless. All other cases the above succeeds. */ pipe = usb_sndbulkpipe (serial->dev, 7); ret = usb_bulk_msg (serial->dev, pipe, command, sizeof(command), &alen, 2 * HZ); if (ret) { err("%s: Couldn't send command [%d]", serial->type->name, ret); goto error_out; } else if (alen != sizeof(command)) { err("%s: Send command incomplete [%d]", serial->type->name, alen); goto error_out; } pipe = usb_rcvbulkpipe (serial->dev, 7); ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, 2 * HZ); if (ret) { err("%s: Couldn't get results [%d]", serial->type->name, ret); goto error_out; } else if (alen != sizeof(result)) { err("%s: Get results incomplete [%d]", serial->type->name, alen); goto error_out; } else if (result[0] != command[0]) { err("%s: Command failed [%d]", serial->type->name, result[0]); goto error_out; } hw_info = (struct whiteheat_hw_info *)&result[1]; info("%s: Driver %s: Firmware v%d.%02d", serial->type->name, DRIVER_VERSION, hw_info->sw_major_rev, hw_info->sw_minor_rev); return 0;error_out: err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->name); /* * Return that we've claimed the interface. A failure here may be * due to interception by the command_callback routine or other * causes that don't mean that the firmware isn't running. This may * change in the future. Probably should actually. */ return 0;}static void whiteheat_real_shutdown (struct usb_serial *serial){ struct usb_serial_port *command_port; dbg("%s", __FUNCTION__); /* free up our private data for our command port */ command_port = &serial->port[COMMAND_PORT]; if (command_port->private != NULL) { kfree (command_port->private); command_port->private = NULL; } return;}static void set_command (struct usb_serial_port *port, unsigned char state, unsigned char command){ struct whiteheat_rdb_set rdb_command; /* send a set rts command to the port */ /* firmware uses 1 based port numbering */ rdb_command.port = port->number - port->serial->minor + 1; rdb_command.state = state; whiteheat_send_cmd (port->serial, command, (__u8 *)&rdb_command, sizeof(rdb_command));}static inline void set_rts (struct usb_serial_port *port, unsigned char rts){ set_command (port, rts, WHITEHEAT_SET_RTS);}static inline void set_dtr (struct usb_serial_port *port, unsigned char dtr){ set_command (port, dtr, WHITEHEAT_SET_DTR);}static inline void set_break (struct usb_serial_port *port, unsigned char brk){ set_command (port, brk, WHITEHEAT_SET_BREAK);}static int __init whiteheat_init (void){ usb_serial_register (&whiteheat_fake_device); usb_serial_register (&whiteheat_device); info(DRIVER_DESC " " DRIVER_VERSION); return 0;}static void __exit whiteheat_exit (void){ 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_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug enabled or not");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -