// SPDX-License-Identifier: GPL-2.0+ /* * Edgeport USB Serial Converter driver * * Copyright (C) 2000 Inside Out Networks, All rights reserved. * Copyright (C) 2001-2002 Greg Kroah-Hartman <[email protected]> * * Supports the following devices: * Edgeport/4 * Edgeport/4t * Edgeport/2 * Edgeport/4i * Edgeport/2i * Edgeport/421 * Edgeport/21 * Rapidport/4 * Edgeport/8 * Edgeport/2D8 * Edgeport/4D8 * Edgeport/8i * * For questions or problems with this driver, contact Inside Out * Networks technical support, or Peter Berger <[email protected]>, * or Al Borchers <[email protected]>. * */ #include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/errno.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> #include <linux/serial.h> #include <linux/ioctl.h> #include <linux/wait.h> #include <linux/firmware.h> #include <linux/ihex.h> #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/usb/serial.h> #include "io_edgeport.h" #include "io_ionsp.h" /* info for the iosp messages */ #include "io_16654.h" /* 16654 UART defines */ #define DRIVER_AUTHOR … #define DRIVER_DESC … #define MAX_NAME_LEN … #define OPEN_TIMEOUT … static const struct usb_device_id edgeport_2port_id_table[] = …; static const struct usb_device_id edgeport_4port_id_table[] = …; static const struct usb_device_id edgeport_8port_id_table[] = …; static const struct usb_device_id Epic_port_id_table[] = …; /* Devices that this driver supports */ static const struct usb_device_id id_table_combined[] = …; MODULE_DEVICE_TABLE(usb, id_table_combined); /* receive port state */ enum RXSTATE { … }; /* Transmit Fifo * This Transmit queue is an extension of the edgeport Rx buffer. * The maximum amount of data buffered in both the edgeport * Rx buffer (maxTxCredits) and this buffer will never exceed maxTxCredits. */ struct TxFifo { … }; /* This structure holds all of the local port information */ struct edgeport_port { … }; /* This structure holds all of the individual device information */ struct edgeport_serial { … }; /* baud rate information */ struct divisor_table_entry { … }; /* * Define table of divisors for Rev A EdgePort/4 hardware * These assume a 3.6864MHz crystal, the standard /16, and * MCR.7 = 0. */ static const struct divisor_table_entry divisor_table[] = …; /* Number of outstanding Command Write Urbs */ static atomic_t CmdUrbs = …; /* function prototypes */ static void edge_close(struct usb_serial_port *port); static void process_rcvd_data(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength); static void process_rcvd_status(struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3); static void edge_tty_recv(struct usb_serial_port *port, unsigned char *data, int length); static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr); static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data); static int send_iosp_ext_cmd(struct edgeport_port *edge_port, __u8 command, __u8 param); static int calc_baud_rate_divisor(struct device *dev, int baud_rate, int *divisor); static void change_port_settings(struct tty_struct *tty, struct edgeport_port *edge_port, const struct ktermios *old_termios); static int send_cmd_write_uart_register(struct edgeport_port *edge_port, __u8 regNum, __u8 regValue); static int write_cmd_usb(struct edgeport_port *edge_port, unsigned char *buffer, int writeLength); static void send_more_port_data(struct edgeport_serial *edge_serial, struct edgeport_port *edge_port); static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, const __u8 *data); /* ************************************************************************ */ /* ************************************************************************ */ /* ************************************************************************ */ /* ************************************************************************ */ /************************************************************************ * * * update_edgeport_E2PROM() Compare current versions of * * Boot ROM and Manufacture * * Descriptors with versions * * embedded in this driver * * * ************************************************************************/ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial) { … } static void dump_product_info(struct edgeport_serial *edge_serial, struct edgeport_product_info *product_info) { … } static void get_product_info(struct edgeport_serial *edge_serial) { … } static int get_epic_descriptor(struct edgeport_serial *ep) { … } /************************************************************************/ /************************************************************************/ /* U S B C A L L B A C K F U N C T I O N S */ /* U S B C A L L B A C K F U N C T I O N S */ /************************************************************************/ /************************************************************************/ /***************************************************************************** * edge_interrupt_callback * this is the callback function for when we have received data on the * interrupt endpoint. *****************************************************************************/ static void edge_interrupt_callback(struct urb *urb) { … } /***************************************************************************** * edge_bulk_in_callback * this is the callback function for when we have received data on the * bulk in endpoint. *****************************************************************************/ static void edge_bulk_in_callback(struct urb *urb) { … } /***************************************************************************** * edge_bulk_out_data_callback * this is the callback function for when we have finished sending * serial data on the bulk out endpoint. *****************************************************************************/ static void edge_bulk_out_data_callback(struct urb *urb) { … } /***************************************************************************** * BulkOutCmdCallback * this is the callback function for when we have finished sending a * command on the bulk out endpoint. *****************************************************************************/ static void edge_bulk_out_cmd_callback(struct urb *urb) { … } /***************************************************************************** * Driver tty interface functions *****************************************************************************/ /***************************************************************************** * SerialOpen * this function is called by the tty driver when a port is opened * If successful, we return 0 * Otherwise we return a negative error number. *****************************************************************************/ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) { … } /************************************************************************ * * block_until_chase_response * * This function will block the close until one of the following: * 1. Response to our Chase comes from Edgeport * 2. A timeout of 10 seconds without activity has expired * (1K of Edgeport data @ 2400 baud ==> 4 sec to empty) * ************************************************************************/ static void block_until_chase_response(struct edgeport_port *edge_port) { … } /************************************************************************ * * block_until_tx_empty * * This function will block the close until one of the following: * 1. TX count are 0 * 2. The edgeport has stopped * 3. A timeout of 3 seconds without activity has expired * ************************************************************************/ static void block_until_tx_empty(struct edgeport_port *edge_port) { … } /***************************************************************************** * edge_close * this function is called by the tty driver when a port is closed *****************************************************************************/ static void edge_close(struct usb_serial_port *port) { … } /***************************************************************************** * SerialWrite * this function is called by the tty driver when data should be written * to the port. * If successful, we return the number of bytes written, otherwise we * return a negative error number. *****************************************************************************/ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *data, int count) { … } /************************************************************************ * * send_more_port_data() * * This routine attempts to write additional UART transmit data * to a port over the USB bulk pipe. It is called (1) when new * data has been written to a port's TxBuffer from higher layers * (2) when the peripheral sends us additional TxCredits indicating * that it can accept more Tx data for a given port; and (3) when * a bulk write completes successfully and we want to see if we * can transmit more. * ************************************************************************/ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edgeport_port *edge_port) { … } /***************************************************************************** * edge_write_room * this function is called by the tty driver when it wants to know how * many bytes of data we can accept for a specific port. *****************************************************************************/ static unsigned int edge_write_room(struct tty_struct *tty) { … } /***************************************************************************** * edge_chars_in_buffer * this function is called by the tty driver when it wants to know how * many bytes of data we currently have outstanding in the port (data that * has been written, but hasn't made it out the port yet) *****************************************************************************/ static unsigned int edge_chars_in_buffer(struct tty_struct *tty) { … } /***************************************************************************** * SerialThrottle * this function is called by the tty driver when it wants to stop the data * being read from the port. *****************************************************************************/ static void edge_throttle(struct tty_struct *tty) { … } /***************************************************************************** * edge_unthrottle * this function is called by the tty driver when it wants to resume the * data being read from the port (called after SerialThrottle is called) *****************************************************************************/ static void edge_unthrottle(struct tty_struct *tty) { … } /***************************************************************************** * SerialSetTermios * this function is called by the tty driver when it wants to change * the termios structure *****************************************************************************/ static void edge_set_termios(struct tty_struct *tty, struct usb_serial_port *port, const struct ktermios *old_termios) { … } /***************************************************************************** * get_lsr_info - get line status register info * * Purpose: Let user call ioctl() to get info when the UART physically * is emptied. On bus types like RS485, the transmitter must * release the bus after transmitting. This must be done when * the transmit shift register is empty, not be done when the * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. *****************************************************************************/ static int get_lsr_info(struct edgeport_port *edge_port, unsigned int __user *value) { … } static int edge_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { … } static int edge_tiocmget(struct tty_struct *tty) { … } /***************************************************************************** * SerialIoctl * this function handles any ioctl calls to the driver *****************************************************************************/ static int edge_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { … } /***************************************************************************** * SerialBreak * this function sends a break to the port *****************************************************************************/ static int edge_break(struct tty_struct *tty, int break_state) { … } /***************************************************************************** * process_rcvd_data * this function handles the data received on the bulk in pipe. *****************************************************************************/ static void process_rcvd_data(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength) { … } /***************************************************************************** * process_rcvd_status * this function handles the any status messages received on the * bulk in pipe. *****************************************************************************/ static void process_rcvd_status(struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3) { … } /***************************************************************************** * edge_tty_recv * this function passes data on to the tty flip buffer *****************************************************************************/ static void edge_tty_recv(struct usb_serial_port *port, unsigned char *data, int length) { … } /***************************************************************************** * handle_new_msr * this function handles any change to the msr register for a port. *****************************************************************************/ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) { … } /***************************************************************************** * handle_new_lsr * this function handles any change to the lsr register for a port. *****************************************************************************/ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data) { … } /**************************************************************************** * sram_write * writes a number of bytes to the Edgeport device's sram starting at the * given address. * If successful returns the number of bytes written, otherwise it returns * a negative error number of the problem. ****************************************************************************/ static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, const __u8 *data) { … } /**************************************************************************** * rom_write * writes a number of bytes to the Edgeport device's ROM starting at the * given address. * If successful returns the number of bytes written, otherwise it returns * a negative error number of the problem. ****************************************************************************/ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, const __u8 *data) { … } /**************************************************************************** * rom_read * reads a number of bytes from the Edgeport device starting at the given * address. * Returns zero on success or a negative error number. ****************************************************************************/ static int rom_read(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data) { … } /**************************************************************************** * send_iosp_ext_cmd * Is used to send a IOSP message to the Edgeport device ****************************************************************************/ static int send_iosp_ext_cmd(struct edgeport_port *edge_port, __u8 command, __u8 param) { … } /***************************************************************************** * write_cmd_usb * this function writes the given buffer out to the bulk write endpoint. *****************************************************************************/ static int write_cmd_usb(struct edgeport_port *edge_port, unsigned char *buffer, int length) { … } /***************************************************************************** * send_cmd_write_baud_rate * this function sends the proper command to change the baud rate of the * specified port. *****************************************************************************/ static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, int baudRate) { … } /***************************************************************************** * calc_baud_rate_divisor * this function calculates the proper baud rate divisor for the specified * baud rate. *****************************************************************************/ static int calc_baud_rate_divisor(struct device *dev, int baudrate, int *divisor) { … } /***************************************************************************** * send_cmd_write_uart_register * this function builds up a uart register message and sends to the device. *****************************************************************************/ static int send_cmd_write_uart_register(struct edgeport_port *edge_port, __u8 regNum, __u8 regValue) { … } /***************************************************************************** * change_port_settings * This routine is called to set the UART on the device to match the * specified new settings. *****************************************************************************/ static void change_port_settings(struct tty_struct *tty, struct edgeport_port *edge_port, const struct ktermios *old_termios) { … } /**************************************************************************** * unicode_to_ascii * Turns a string from Unicode into ASCII. * Doesn't do a good job with any characters that are outside the normal * ASCII range, but it's only for debugging... * NOTE: expects the unicode in LE format ****************************************************************************/ static void unicode_to_ascii(char *string, int buflen, __le16 *unicode, int unicode_size) { … } /**************************************************************************** * get_manufacturing_desc * reads in the manufacturing descriptor and stores it into the serial * structure. ****************************************************************************/ static void get_manufacturing_desc(struct edgeport_serial *edge_serial) { … } /**************************************************************************** * get_boot_desc * reads in the bootloader descriptor and stores it into the serial * structure. ****************************************************************************/ static void get_boot_desc(struct edgeport_serial *edge_serial) { … } /**************************************************************************** * load_application_firmware * This is called to load the application firmware to the device ****************************************************************************/ static void load_application_firmware(struct edgeport_serial *edge_serial) { … } /**************************************************************************** * edge_startup ****************************************************************************/ static int edge_startup(struct usb_serial *serial) { … } /**************************************************************************** * edge_disconnect * This function is called whenever the device is removed from the usb bus. ****************************************************************************/ static void edge_disconnect(struct usb_serial *serial) { … } /**************************************************************************** * edge_release * This function is called when the device structure is deallocated. ****************************************************************************/ static void edge_release(struct usb_serial *serial) { … } static int edge_port_probe(struct usb_serial_port *port) { … } static void edge_port_remove(struct usb_serial_port *port) { … } static struct usb_serial_driver edgeport_2port_device = …; static struct usb_serial_driver edgeport_4port_device = …; static struct usb_serial_driver edgeport_8port_device = …; static struct usb_serial_driver epic_device = …; static struct usb_serial_driver * const serial_drivers[] = …; module_usb_serial_driver(…); MODULE_AUTHOR(…); MODULE_DESCRIPTION(…); MODULE_LICENSE(…) …; MODULE_FIRMWARE(…) …; MODULE_FIRMWARE(…) …; MODULE_FIRMWARE(…) …; MODULE_FIRMWARE(…) …;