diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2007-01-04 16:55:20 -0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-01-04 16:55:20 -0800 |
| commit | a88452c7db70791f9febf76174c4c928c903444e (patch) | |
| tree | 97a60640b4b18692acde21e3e185cb819518ef4a /bad | |
| parent | aa79741c8ee7af51c5ca9e47387154f260b745c3 (diff) | |
| download | patches-a88452c7db70791f9febf76174c4c928c903444e.tar.gz | |
add a few more patches
Diffstat (limited to 'bad')
| -rw-r--r-- | bad/usb-serial-serqt_usb.patch | 3034 |
1 files changed, 3034 insertions, 0 deletions
diff --git a/bad/usb-serial-serqt_usb.patch b/bad/usb-serial-serqt_usb.patch new file mode 100644 index 00000000000000..1fd0227afac139 --- /dev/null +++ b/bad/usb-serial-serqt_usb.patch @@ -0,0 +1,3034 @@ +From: Greg Kroah-Hartman <gregkh@suse.de> +Subject: USB: add USB serial Quatech driver + +Add support for all Quatech usb to serial devices. + +Based on an original driver from Quatech. + +Cleaned up and forward ported by me. + +(yes, I know it still doesn't follow coding standard, and it doesn't use +the usb-serial layer, but I'm still fixing it up...) + +Cc: Tim Gobeli <tgobeli@quatech.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/Kconfig | 10 + drivers/usb/serial/Makefile | 1 + drivers/usb/serial/serqt_usb.c | 2981 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 2992 insertions(+) + +--- gregkh-2.6.orig/drivers/usb/serial/Kconfig ++++ gregkh-2.6/drivers/usb/serial/Kconfig +@@ -464,6 +464,16 @@ config USB_SERIAL_PL2303 + To compile this driver as a module, choose M here: the + module will be called pl2303. + ++config USB_SERIAL_QUATECH_ESU100 ++ tristate "USB Quatech ESU-100 8 Port Serial Driver" ++ depends on USB_SERIAL ++ help ++ Say Y here if you want to use the Quatech ESU-100 8 port usb to ++ serial adapter. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called serqt_usb. ++ + config USB_SERIAL_HP4X + tristate "USB HP4x Calculators support" + depends on USB_SERIAL +--- gregkh-2.6.orig/drivers/usb/serial/Makefile ++++ gregkh-2.6/drivers/usb/serial/Makefile +@@ -41,6 +41,7 @@ obj-$(CONFIG_USB_SERIAL_NAVMAN) += nav + obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o + obj-$(CONFIG_USB_SERIAL_OPTION) += option.o + obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o ++obj-$(CONFIG_USB_SERIAL_QUATECH_ESU100) += serqt_usb.o + obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o + obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o + obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o +--- /dev/null ++++ gregkh-2.6/drivers/usb/serial/serqt_usb.c +@@ -0,0 +1,2981 @@ ++/* ++ * This code was developed for the Quatech USB line for linux, it used ++ * much of the code developed by Greg Kroah-Hartman for USB serial devices ++ * ++ */ ++ ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/module.h> ++#include <linux/usb.h> ++#include <linux/wait.h> ++#include <linux/types.h> ++#include <linux/version.h> ++ ++#include <asm/uaccess.h> ++ ++/* Use our own dbg macro */ ++//#define DEBUG_ON ++//#undef dbg ++#ifdef DEBUG_ON ++ #define mydbg(const...) printk(const) ++#else ++ #define mydbg(const...) ++#endif ++ ++ ++/* parity check flag */ ++#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) ++ ++ ++#define SERIAL_TTY_MAJOR 0 /* Nice legal number now */ ++#define SERIAL_TTY_MINORS 255 /* loads of devices :) */ ++#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */ ++#define PREFUFF_LEVEL_CONSERVATIVE 128 ++#define ATC_DISABLED 0x00 ++ ++#define RR_BITS 0x03 //for clearing clock bits ++#define DUPMODE_BITS 0xc0 ++ ++#define RS232_MODE 0x00 ++#define RTSCTS_TO_CONNECTOR 0x40 ++#define CLKS_X4 0x02 /// ++ ++#define LOOPMODE_BITS 0x41 //LOOP1 = b6, LOOP0 = b0 (PORT B) ++#define ALL_LOOPBACK 0x01 ++#define MODEM_CTRL 0x40 ++ ++ ++#define THISCHAR data[i] ++#define NEXTCHAR data[i + 1] ++#define THIRDCHAR data[i + 2] ++#define FOURTHCHAR data[i + 3] ++ ++//************************************************* ++// Useful defintions for port A, Port B and Port C ++#define FULLPWRBIT 0x00000080 ++#define NEXT_BOARD_POWER_BIT 0x00000004 ++ ++ ++#define SERIAL_LSR_OE 0x02 ++#define SERIAL_LSR_PE 0x04 ++#define SERIAL_LSR_FE 0x08 ++#define SERIAL_LSR_BI 0x10 ++ ++#define SERIAL_LSR_TEMT 0x40 ++ ++#define DIV_LATCH_LS 0x00 ++#define XMT_HOLD_REGISTER 0x00 ++#define XVR_BUFFER_REGISTER 0x00 ++#define DIV_LATCH_MS 0x01 ++#define FIFO_CONTROL_REGISTER 0x02 ++#define LINE_CONTROL_REGISTER 0x03 ++#define MODEM_CONTROL_REGISTER 0x04 ++#define LINE_STATUS_REGISTER 0x05 ++#define MODEM_STATUS_REGISTER 0x06 ++ ++ ++#define SERIAL_MCR_DTR 0x01 ++#define SERIAL_MCR_RTS 0x02 ++#define SERIAL_MCR_LOOP 0x10 ++ ++#define SERIAL_MSR_CTS 0x10 ++#define SERIAL_MSR_CD 0x80 ++#define SERIAL_MSR_RI 0x40 ++#define SERIAL_MSR_DSR 0x20 ++#define SERIAL_MSR_MASK 0xf0 ++ ++#define SERIAL_8_DATA 0x03 ++#define SERIAL_7_DATA 0x02 ++#define SERIAL_6_DATA 0x01 ++#define SERIAL_5_DATA 0x00 ++ ++#define SERIAL_ODD_PARITY 0X08 ++#define SERIAL_EVEN_PARITY 0X18 ++#define SERIAL_TWO_STOPB 0x04 ++#define SERIAL_ONE_STOPB 0x00 ++ ++#define MAX_BAUD_RATE 460800 ++#define MAX_BAUD_REMAINDER 4608 ++ ++ ++#define QT_SET_GET_DEVICE 0xc2 ++#define QT_OPEN_CLOSE_CHANNEL 0xca ++#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc ++#define QT_SET_ATF 0xcd ++#define QT_GET_SET_REGISTER 0xc0 ++#define QT_GET_SET_UART 0xc1 ++#define QT_HW_FLOW_CONTROL_MASK 0xc5 ++#define QT_SW_FLOW_CONTROL_MASK 0xc6 ++#define QT_SW_FLOW_CONTROL_DISABLE 0xc7 ++#define QT_BREAK_CONTROL 0xc8 ++ ++#define SERIALQT_PCI_IOC_MAGIC 'k' ++#define SERIALQT_WRITE_QOPR _IOW(SERIALQT_PCI_IOC_MAGIC, 0, int) ++#define SERIALQT_WRITE_QMCR _IOW(SERIALQT_PCI_IOC_MAGIC, 1, int) ++#define SERIALQT_GET_NUMOF_UNITS _IOR(SERIALQT_PCI_IOC_MAGIC, 2, void *) ++#define SERIALQT_GET_THIS_UNIT _IOR(SERIALQT_PCI_IOC_MAGIC, 3, void *) ++#define SERIALQT_READ_QOPR _IOR(SERIALQT_PCI_IOC_MAGIC, 4, int) ++#define SERIALQT_READ_QMCR _IOR(SERIALQT_PCI_IOC_MAGIC, 5, int) ++#define SERIALQT_IS422_EXTENDED _IOR(SERIALQT_PCI_IOC_MAGIC, 6, int) //returns successful if 422 extended ++ ++ ++#define USBD_TRANSFER_DIRECTION_IN 0xc0 ++#define USBD_TRANSFER_DIRECTION_OUT 0x40 ++ ++#define ATC_DISABLED 0x00 ++#define ATC_RTS_ENABLED 0x02 ++#define ATC_DTR_ENABLED 0x01 ++ ++#define RR_BITS 0x03 //for clearing clock bits ++#define DUPMODE_BITS 0xc0 ++ ++#define FULL_DUPLEX 0x00 ++#define HALF_DUPLEX_RTS 0x40 ++#define HALF_DUPLEX_DTR 0x80 ++ ++#define QMCR_FULL_DUPLEX 0x00 ++#define QMCR_HALF_DUPLEX_RTS 0x02 ++#define QMCR_HALF_DUPLEX_DTR 0x01 ++#define QMCR_HALF_DUPLEX_MASK 0x03 ++#define QMCR_CONNECTOR_MASK 0x1C ++ ++#define QMCR_RX_EN_MASK 0x20 ++ ++#define QMCR_ALL_LOOPBACK 0x10 ++#define QMCR_MODEM_CONTROL 0X00 ++ ++ ++ ++#define SERIALQT_IOC_MAXNR 6 ++ ++struct usb_serial_port { ++ struct usb_serial *serial; /* pointer back to the owner of this port */ ++ struct tty_struct * tty; /* the coresponding tty for this port */ ++ unsigned char number; ++ char active; /* someone has this device open */ ++ ++ unsigned char * interrupt_in_buffer; ++ struct urb * interrupt_in_urb; ++ __u8 interrupt_in_endpointAddress; ++ ++ unsigned char * bulk_in_buffer; ++ unsigned char * xfer_to_tty_buffer; ++ struct urb * read_urb; ++ __u8 bulk_in_endpointAddress; ++ ++ unsigned char * bulk_out_buffer; ++ int bulk_out_size; ++ struct urb * write_urb; ++ __u8 bulk_out_endpointAddress; ++ ++ wait_queue_head_t write_wait; ++ wait_queue_head_t wait; ++ struct work_struct work; ++ ++ int open_count; /* number of times this port has been opened */ ++ struct semaphore sem; /* locks this structure */ ++ ++ __u8 shadowLCR; /* last LCR value received */ ++ __u8 shadowMCR; /* last MCR value received */ ++ __u8 shadowMSR; /* last MSR value received */ ++ __u8 shadowLSR; /* last LSR value received */ ++ int RxHolding; ++ char closePending; ++ int ReadBulkStopped; ++ ++ void * private; /* data private to the specific port */ ++}; ++ ++struct identity { ++ int index; ++ int n_identity; ++}; ++ ++struct usb_serial { ++ struct usb_device * dev; ++ struct usb_interface * interface; /* the interface for this device */ ++ struct tty_driver * tty_driver; /* the tty_driver for this device */ ++ unsigned char minor; /* the starting minor number for this device */ ++ unsigned char num_ports; /* the number of ports this device has */ ++ char num_interrupt_in; /* number of interrupt in endpoints we have */ ++ char num_bulk_in; /* number of bulk in endpoints we have */ ++ char num_bulk_out; /* number of bulk out endpoints we have */ ++ unsigned char num_OpenCount; /* the number of ports this device has */ ++ ++ ++ __u16 vendor; /* vendor id of this device */ ++ __u16 product; /* product id of this device */ ++ struct usb_serial_port port[MAX_NUM_PORTS]; ++ ++ void * private; /* data private to the specific driver */ ++}; ++ ++ ++ ++static inline int port_paranoia_check (struct usb_serial_port *port, const char *function) ++{ ++ if (!port) { ++ dbg("%s - port == NULL", function); ++ return -1; ++ } ++ if (!port->serial) { ++ dbg("%s - port->serial == NULL\n", function); ++ return -1; ++ } ++ if (!port->tty) { ++ dbg("%s - port->tty == NULL\n", function); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++/* Inline functions to check the sanity of a pointer that is passed to us */ ++static inline int serial_paranoia_check (struct usb_serial *serial, const char *function) ++{ ++ if (!serial) { ++ dbg("%s - serial == NULL\n", function); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function) ++{ ++ /* if no port was specified, or it fails a paranoia check */ ++ if (!port || ++ port_paranoia_check (port, function) || ++ serial_paranoia_check (port->serial, function)) { ++ /* then say that we dont have a valid usb_serial thing, which will ++ * end up genrating -ENODEV return values */ ++ return NULL; ++ } ++ ++ return port->serial; ++} ++ ++ ++struct qt_get_device_data ++{ ++ __u8 porta; ++ __u8 portb; ++ __u8 portc; ++}; ++ ++struct qt_open_channel_data ++{ ++ __u8 line_status; ++ __u8 modem_status; ++}; ++ ++static void ProcessLineStatus(struct usb_serial_port *port, unsigned char line_status); ++static void ProcessModemStatus(struct usb_serial_port *port, unsigned char modem_status); ++static void ProcessRxChar(struct usb_serial_port *port, unsigned char Data); ++static struct usb_serial *get_free_serial (int num_ports, int *minor); ++ ++ ++static int serqt_probe(struct usb_interface *interface, ++ const struct usb_device_id *id); ++ ++ ++static void serqt_usb_disconnect(struct usb_interface *interface); ++static int box_set_device(struct usb_serial *serial, struct qt_get_device_data *pDeviceData); ++static int box_get_device(struct usb_serial *serial, struct qt_get_device_data *pDeviceData); ++static int serial_open (struct tty_struct *tty, struct file * filp); ++static void serial_close(struct tty_struct *tty, struct file * filp); ++static int serial_write_room (struct tty_struct *tty); ++static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg); ++static void serial_set_termios (struct tty_struct *tty, struct ktermios * old); ++static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count); ++ ++static void serial_throttle (struct tty_struct * tty); ++static void serial_unthrottle (struct tty_struct * tty); ++static void serial_break (struct tty_struct *tty, int break_state); ++static int serial_chars_in_buffer (struct tty_struct *tty); ++static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data); ++ ++static int qt_open (struct usb_serial_port *port, struct file *filp); ++static int BoxSetPrebufferLevel(struct usb_serial *serial); ++ ++static int BoxSetATC(struct usb_serial *serial, __u16 n_Mode); ++static int BoxSetUart(struct usb_serial *serial, unsigned short Uart_Number, unsigned short default_divisor, unsigned char default_LCR ); ++ ++ ++static int BoxOPenCloseChannel(struct usb_serial *serial, __u16 Uart_Number, __u16 OpenClose, struct qt_open_channel_data *pDeviceData); ++static void qt_close (struct usb_serial_port *port, struct file * filp); ++static int BoxGetRegister(struct usb_serial *serial, unsigned short Uart_Number,unsigned short Register_Num, __u8 *pValue); ++static int BoxSetRegister(struct usb_serial *serial, unsigned short Uart_Number, unsigned short Register_Num, unsigned short Value ); ++static void qt_write_bulk_callback(struct urb *urb); ++static int qt_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); ++static void port_softint(struct work_struct *work); ++static int qt_write_room (struct usb_serial_port *port); ++static int qt_chars_in_buffer (struct usb_serial_port *port); ++static int qt_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); ++static void qt_set_termios(struct usb_serial_port *port, struct ktermios *old_termios); ++static int BoxSetHW_FlowCtrl(struct usb_serial *serial, unsigned int UartNumber, int bSet); ++static int BoxDisable_SW_FlowCtrl(struct usb_serial *serial, __u16 UartNumber); ++static int EmulateWriteQMCR_Reg(int index, unsigned uc_value); ++static int EmulateReadQMCR_Reg(int index, unsigned *uc_value); ++static struct usb_serial *find_the_box(unsigned int index); ++int ioctl_serial_usb (struct inode *innod, struct file *filp, unsigned int cmd, unsigned long arg); ++ ++ ++static int BoxSetSW_FlowCtrl(struct usb_serial *serial, __u16 Uart, unsigned char stop_char, unsigned char start_char); ++static void qt_read_bulk_callback(struct urb *urb); ++ ++static void port_sofrint(void *private); ++ ++static void return_serial(struct usb_serial *serial); ++ ++ ++static int serial_tiocmset (struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); ++static int serial_tiocmget(struct tty_struct *tty, struct file *file); ++ ++ ++ ++static int qt_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int value); ++ ++static int qt_tiocmget(struct usb_serial_port *port, struct file * file); ++ ++ ++ ++/* Version Information */ ++#define DRIVER_VERSION "v2.14" ++#define DRIVER_AUTHOR "Tim Gobeli, Quatech, Inc" ++#define DRIVER_DESC "Quatech USB to Serial Driver" ++ ++#define USB_VENDOR_ID_QUATECH 0x061d // Quatech VID ++#define DEVICE_ID_QUATECH_RS232_SINGLE_PORT 0xC020 //SSU100 ++#define DEVICE_ID_QUATECH_RS422_SINGLE_PORT 0xC030 //SSU200 ++#define DEVICE_ID_QUATECH_RS232_DUAL_PORT 0xC040 //DSU100 ++#define DEVICE_ID_QUATECH_RS422_DUAL_PORT 0xC050 //DSU200 ++#define DEVICE_ID_QUATECH_RS232_FOUR_PORT 0xC060 //QSU100 ++#define DEVICE_ID_QUATECH_RS422_FOUR_PORT 0xC070 //QSU200 ++#define DEVICE_ID_QUATECH_RS232_EIGHT_PORT_A 0xC080 //ESU100A ++#define DEVICE_ID_QUATECH_RS232_EIGHT_PORT_B 0xC081 //ESU100B ++#define DEVICE_ID_QUATECH_RS422_EIGHT_PORT_A 0xC0A0 //ESU200A ++#define DEVICE_ID_QUATECH_RS422_EIGHT_PORT_B 0xC0A1 //ESU200B ++#define DEVICE_ID_QUATECH_RS232_16_PORT_A 0xC090 //HSU100A ++#define DEVICE_ID_QUATECH_RS232_16_PORT_B 0xC091 //HSU100B ++#define DEVICE_ID_QUATECH_RS232_16_PORT_C 0xC092 //HSU100C ++#define DEVICE_ID_QUATECH_RS232_16_PORT_D 0xC093 //HSU100D ++#define DEVICE_ID_QUATECH_RS422_16_PORT_A 0xC0B0 //HSU200A ++#define DEVICE_ID_QUATECH_RS422_16_PORT_B 0xC0B1 //HSU200B ++#define DEVICE_ID_QUATECH_RS422_16_PORT_C 0xC0B2 //HSU200C ++#define DEVICE_ID_QUATECH_RS422_16_PORT_D 0xC0B3 //HSU200D ++ ++ ++/* table of Quatech devices */ ++static struct usb_device_id serqt_table [] = { ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_SINGLE_PORT)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_SINGLE_PORT)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_DUAL_PORT)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_DUAL_PORT)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_FOUR_PORT)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_FOUR_PORT)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_EIGHT_PORT_A)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_EIGHT_PORT_B)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_EIGHT_PORT_A)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_EIGHT_PORT_B)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_16_PORT_A)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_16_PORT_B)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_16_PORT_C)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS232_16_PORT_D)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_16_PORT_A)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_16_PORT_B)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_16_PORT_C)}, ++ { USB_DEVICE(USB_VENDOR_ID_QUATECH, DEVICE_ID_QUATECH_RS422_16_PORT_D)}, ++ {} /* Terminating entry */ ++}; ++MODULE_DEVICE_TABLE(usb, serqt_table); ++ ++static int major_number; ++static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ ++ ++ ++/* table of Quatech 422devices */ ++static unsigned int serqt_422_table[] = { ++ DEVICE_ID_QUATECH_RS422_SINGLE_PORT, ++ DEVICE_ID_QUATECH_RS422_DUAL_PORT, ++ DEVICE_ID_QUATECH_RS422_FOUR_PORT, ++ DEVICE_ID_QUATECH_RS422_EIGHT_PORT_A, ++ DEVICE_ID_QUATECH_RS422_EIGHT_PORT_B, ++ DEVICE_ID_QUATECH_RS422_16_PORT_A, ++ DEVICE_ID_QUATECH_RS422_16_PORT_B, ++ DEVICE_ID_QUATECH_RS422_16_PORT_C, ++ DEVICE_ID_QUATECH_RS422_16_PORT_D, ++ 0 /* terminate with zero */ ++}; ++ ++ ++ ++/* usb specific object needed to register this driver with the usb subsystem */ ++static struct usb_driver serqt_usb_driver = { ++ .name = "quatech-usb-serial", ++ .probe = serqt_probe, ++ .disconnect = serqt_usb_disconnect, ++ .id_table = serqt_table, ++}; ++ ++static struct ktermios *serial_termios[SERIAL_TTY_MINORS]; ++static struct ktermios *serial_termios_locked[SERIAL_TTY_MINORS]; ++ ++static struct tty_driver serial_tty_driver = { ++ .magic = TTY_DRIVER_MAGIC, ++ .driver_name = "Quatech usb-serial", ++ .name = "ttyQT_USB", ++ .major = SERIAL_TTY_MAJOR, ++ .minor_start = 0, ++ .num = SERIAL_TTY_MINORS, ++ .type = TTY_DRIVER_TYPE_SERIAL, ++ .subtype = SERIAL_TYPE_NORMAL, ++ .flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV, ++ ++ .termios = serial_termios, ++ .termios_locked = serial_termios_locked, ++ .tiocmset = serial_tiocmset, ++ .tiocmget = serial_tiocmget, ++ .init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL, ++ ++ .init_termios.c_iflag = ICRNL | IXON, ++ .init_termios.c_oflag = OPOST, ++ ++ .init_termios.c_lflag= ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN, ++ ++ ++ ++ ++ .open = serial_open, ++ .close = serial_close, ++ .write = serial_write, ++ .write_room = serial_write_room, ++ .ioctl = serial_ioctl, ++ .set_termios = serial_set_termios, ++ .throttle = serial_throttle, ++ .unthrottle = serial_unthrottle, ++ .break_ctl = serial_break, ++ .chars_in_buffer = serial_chars_in_buffer, ++ .read_proc = serial_read_proc, ++}; ++ ++//fops for parent device ++struct file_operations serialqt_usb_fops = { ++ .ioctl = ioctl_serial_usb, ++ ++}; ++ ++ ++ /** ++ * serqt_probe ++ * ++ * Called by the usb core when a new device is connected that it thinks ++ * this driver might be interested in. ++ * ++ */ ++static int serqt_probe(struct usb_interface *interface, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *dev = interface_to_usbdev(interface); ++ struct usb_serial *serial = NULL; ++ struct usb_serial_port *port; ++ struct usb_endpoint_descriptor *endpoint; ++ struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS]; ++ struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS]; ++ struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; ++ int minor; ++ int buffer_size; ++ int i; ++ struct usb_host_interface *iface_desc; ++ int num_interrupt_in = 0; ++ int num_bulk_in = 0; ++ int num_bulk_out = 0; ++ int num_ports; ++ struct qt_get_device_data DeviceData; ++ int status; ++ ++ mydbg("In %s\n", __FUNCTION__); ++ ++ /* let's find the endpoints needed */ ++ /* check out the endpoints */ ++ iface_desc = interface->cur_altsetting;; ++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) ++ { ++ endpoint = &iface_desc->endpoint[i].desc; ++ ++ if ((endpoint->bEndpointAddress & 0x80) && ++ ((endpoint->bmAttributes & 3) == 0x02)) ++ { ++ /* we found a bulk in endpoint */ ++ mydbg("found bulk in"); ++ bulk_in_endpoint[num_bulk_in] = endpoint; ++ ++num_bulk_in; ++ } ++ ++ if (((endpoint->bEndpointAddress & 0x80) == 0x00) && ++ ((endpoint->bmAttributes & 3) == 0x02)) ++ { ++ /* we found a bulk out endpoint */ ++ mydbg("found bulk out\n"); ++ bulk_out_endpoint[num_bulk_out] = endpoint; ++ ++num_bulk_out; ++ } ++ ++ if ((endpoint->bEndpointAddress & 0x80) && ++ ((endpoint->bmAttributes & 3) == 0x03)) ++ { ++ /* we found a interrupt in endpoint */ ++ mydbg("found interrupt in\n"); ++ interrupt_in_endpoint[num_interrupt_in] = endpoint; ++ ++num_interrupt_in; ++ } ++ } ++ ++ /* found all that we need */ ++ info("Quatech converter detected"); ++ num_ports = num_bulk_out; ++ if (num_ports == 0) ++ { ++ err("Quatech device with no bulk out, not allowed."); ++ return -ENODEV; ++ ++ } ++ ++ serial = get_free_serial (num_ports, &minor); ++ if (serial == NULL) ++ { ++ err("No more free serial devices"); ++ return -ENODEV; ++ } ++ ++ serial->dev = dev; ++ serial->interface = interface; ++ serial->minor = minor; ++ serial->num_ports = num_ports; ++ serial->num_bulk_in = num_bulk_in; ++ serial->num_bulk_out = num_bulk_out; ++ serial->num_interrupt_in = num_interrupt_in; ++ serial->vendor = dev->descriptor.idVendor; ++ serial->product = dev->descriptor.idProduct; ++ ++ ++ /* set up the endpoint information */ ++ for (i = 0; i < num_bulk_in; ++i) ++ { ++ endpoint = bulk_in_endpoint[i]; ++ port = &serial->port[i]; ++ port->read_urb = usb_alloc_urb (0, GFP_KERNEL); ++ if (!port->read_urb) ++ { ++ err("No free urbs available"); ++ goto probe_error; ++ } ++ buffer_size = endpoint->wMaxPacketSize; ++ port->bulk_in_endpointAddress = endpoint->bEndpointAddress; ++ port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); ++ port->xfer_to_tty_buffer = kmalloc (buffer_size, GFP_KERNEL); ++ if (!port->bulk_in_buffer) ++ { ++ err("Couldn't allocate bulk_in_buffer"); ++ goto probe_error; ++ } ++ usb_fill_bulk_urb (port->read_urb, dev, ++ usb_rcvbulkpipe (dev, ++ endpoint->bEndpointAddress), ++ port->bulk_in_buffer, buffer_size, ++ qt_read_bulk_callback, ++ port); ++ } ++ ++ for (i = 0; i < num_bulk_out; ++i) ++ { ++ endpoint = bulk_out_endpoint[i]; ++ port = &serial->port[i]; ++ port->write_urb = usb_alloc_urb (0, GFP_KERNEL); ++ if (!port->write_urb) ++ { ++ err("No free urbs available"); ++ goto probe_error; ++ } ++ buffer_size = endpoint->wMaxPacketSize; ++ port->bulk_out_size = buffer_size; ++ port->bulk_out_endpointAddress = endpoint->bEndpointAddress; ++ port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL); ++ if (!port->bulk_out_buffer) ++ { ++ err("Couldn't allocate bulk_out_buffer"); ++ goto probe_error; ++ } ++ usb_fill_bulk_urb (port->write_urb, dev, ++ usb_sndbulkpipe (dev, ++ endpoint->bEndpointAddress), ++ port->bulk_out_buffer, buffer_size, ++ qt_write_bulk_callback, ++ port); ++ ++ ++ } ++ ++ //For us numb of bulkin or out = number of ports ++ ++ mydbg("%s - setting up %d port structures for this device\n", __FUNCTION__, num_bulk_in); ++ for (i = 0; i < num_bulk_in; ++i) ++ { ++ port = &serial->port[i]; ++ port->number = i + serial->minor; ++ port->serial = serial; ++ ++ INIT_WORK(&port->work, port_softint); ++ ++ init_MUTEX (&port->sem); ++ ++ ++ ++ } ++ status = box_get_device(serial, &DeviceData); ++ if (status < 0) ++ { ++ mydbg(__FILE__"box_get_device failed"); ++ goto probe_error; ++ } ++ ++ mydbg(__FILE__"DeviceData.portb = 0x%x",DeviceData.portb); ++ ++ DeviceData.portb &= ~FULLPWRBIT; ++ mydbg(__FILE__"Changing DeviceData.portb to 0x%x",DeviceData.portb); ++ ++ status = box_set_device(serial, &DeviceData); ++ if (status < 0) ++ { ++ mydbg(__FILE__"box_set_device failed\n"); ++ goto probe_error; ++ } ++ ++ ++ ++ /* initialize the devfs nodes for this device and let the user know what ports we are bound to */ ++ for (i = 0; i < serial->num_ports; ++i) ++ { ++ info("Converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", ++ serial->port[i].number, serial->port[i].number); ++ } ++ ++ //usb_serial_console_init (debug, minor); ++ ++ ///***********TAG add start next board here ****/// ++ status = box_get_device(serial, &DeviceData); ++ if (status < 0) ++ { ++ mydbg(__FILE__"box_get_device failed"); ++ goto probe_error; ++ } ++ ++ //*****************and before we power up lets initialiaze parnent device stuff here before ++ //*****************we set thmem via any other method such as the property pages ++ switch (serial->product) ++ { ++ case DEVICE_ID_QUATECH_RS232_SINGLE_PORT: ++ case DEVICE_ID_QUATECH_RS232_DUAL_PORT: ++ case DEVICE_ID_QUATECH_RS232_FOUR_PORT: ++ case DEVICE_ID_QUATECH_RS232_EIGHT_PORT_A: ++ case DEVICE_ID_QUATECH_RS232_EIGHT_PORT_B: ++ case DEVICE_ID_QUATECH_RS232_16_PORT_A: ++ case DEVICE_ID_QUATECH_RS232_16_PORT_B: ++ case DEVICE_ID_QUATECH_RS232_16_PORT_C: ++ case DEVICE_ID_QUATECH_RS232_16_PORT_D: ++ DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); ++ DeviceData.porta |= CLKS_X4; ++ DeviceData.portb &= ~(LOOPMODE_BITS); ++ DeviceData.portb |= RS232_MODE; ++ break; ++ ++ ++ case DEVICE_ID_QUATECH_RS422_SINGLE_PORT: ++ case DEVICE_ID_QUATECH_RS422_DUAL_PORT: ++ case DEVICE_ID_QUATECH_RS422_FOUR_PORT: ++ case DEVICE_ID_QUATECH_RS422_EIGHT_PORT_A: ++ case DEVICE_ID_QUATECH_RS422_EIGHT_PORT_B: ++ case DEVICE_ID_QUATECH_RS422_16_PORT_A: ++ case DEVICE_ID_QUATECH_RS422_16_PORT_B: ++ case DEVICE_ID_QUATECH_RS422_16_PORT_C: ++ case DEVICE_ID_QUATECH_RS422_16_PORT_D: ++ DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); ++ DeviceData.porta |= CLKS_X4; ++ DeviceData.portb &= ~(LOOPMODE_BITS); ++ DeviceData.portb |= ALL_LOOPBACK; ++ break; ++ default: ++ DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS); ++ DeviceData.porta |= CLKS_X4; ++ DeviceData.portb &= ~(LOOPMODE_BITS); ++ DeviceData.portb |= RS232_MODE; ++ break; ++ ++ } ++ status = BoxSetPrebufferLevel(serial); //sets to default vaue ++ if (status < 0) ++ { ++ mydbg(__FILE__"BoxSetPrebufferLevel failed\n"); ++ goto probe_error; ++ } ++ ++ status = BoxSetATC(serial, ATC_DISABLED); ++ if (status < 0) ++ { ++ mydbg(__FILE__"BoxSetATC failed\n"); ++ goto probe_error; ++ } ++ //**************************************************************************** ++ mydbg(__FILE__"DeviceData.portb = 0x%x",DeviceData.portb); ++ ++ DeviceData.portb |= NEXT_BOARD_POWER_BIT; ++ mydbg(__FILE__"Changing DeviceData.portb to 0x%x",DeviceData.portb); ++ ++ status = box_set_device(serial, &DeviceData); ++ if (status < 0) ++ { ++ mydbg(__FILE__"box_set_device failed\n"); ++ goto probe_error; ++ } ++ ++ ++ mydbg("Exit Success %s\n", __FUNCTION__); ++ ++ usb_set_intfdata (interface, serial); ++ return 0; ++ ++ ++ ++ probe_error: ++ ++ for (i = 0; i < num_bulk_in; ++i) ++ { ++ port = &serial->port[i]; ++ if (port->read_urb) ++ usb_free_urb (port->read_urb); ++ if (port->bulk_in_buffer) ++ kfree (port->bulk_in_buffer); ++ } ++ for (i = 0; i < num_bulk_out; ++i) ++ { ++ port = &serial->port[i]; ++ if (port->write_urb) ++ usb_free_urb (port->write_urb); ++ if (port->bulk_out_buffer) ++ kfree (port->bulk_out_buffer); ++ ++ if (port->xfer_to_tty_buffer) ++ kfree (port->xfer_to_tty_buffer); ++ } ++ for (i = 0; i < num_interrupt_in; ++i) ++ { ++ port = &serial->port[i]; ++ if (port->interrupt_in_urb) ++ usb_free_urb (port->interrupt_in_urb); ++ if (port->interrupt_in_buffer) ++ kfree (port->interrupt_in_buffer); ++ } ++ ++ ++ /* return the minor range that this device had */ ++ return_serial (serial); ++ mydbg("Exit fail %s\n", __FUNCTION__); ++ ++ /* free up any memory that we allocated */ ++ kfree (serial); ++ return -EIO; ++} ++ ++ ++ ++ ++ ++ ++//returns the serial_table array pointers that are taken ++//up in consecutive positions for each port to a common usb_serial structure ++//back to NULL ++static void return_serial(struct usb_serial *serial) ++{ ++ int i; ++ ++ mydbg("%s\n", __FUNCTION__); ++ ++ if (serial == NULL) ++ return; ++ ++ for (i = 0; i < serial->num_ports; ++i) ++ { ++ serial_table[serial->minor + i] = NULL; ++ } ++ ++ return; ++} ++ ++//Finds the first locatio int the serial_table array where it can fit ++//num_ports number of consecutive points to a common usb_serial structure ++//,allocates a stucture points to it in all the structures, and returns the index ++//to the first location in the array in the "minor" variable. ++ ++static struct usb_serial *get_free_serial (int num_ports, int *minor) ++{ ++ struct usb_serial *serial = NULL; ++ int i, j; ++ int good_spot; ++ ++ mydbg("%s %d\n", __FUNCTION__, num_ports); ++ ++ *minor = 0; ++ for (i = 0; i < SERIAL_TTY_MINORS; ++i) ++ { ++ if (serial_table[i]) ++ continue; ++ ++ good_spot = 1; ++ //find a spot in the array where you can fit consecutive positions ++ //to put the pointers to the usb_serail allocated structure for all ++ //the minor numbers (ie. ports) ++ for (j = 1; j <= num_ports-1; ++j) ++ if (serial_table[i+j]) ++ good_spot = 0; ++ if (good_spot == 0) ++ continue; ++ ++ if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) ++ { ++ err("%s - Out of memory", __FUNCTION__); ++ return NULL; ++ } ++ memset(serial, 0, sizeof(struct usb_serial)); ++ serial_table[i] = serial; ++ *minor = i; ++ mydbg("%s - minor base = %d\n", __FUNCTION__, *minor); ++ //copy in the pointer into the array starting a the *minor position ++ //*minor is the index into the array ++ for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) ++ serial_table[i] = serial; ++ return serial; ++ } ++ return NULL; ++} ++ ++static int flip_that( struct tty_struct *tty, __u16 UartNumber, struct usb_serial *serial) ++{ ++ tty_flip_buffer_push(tty); ++ tty_schedule_flip(tty); ++ return 0; ++} ++ ++//Handles processing and moving data to the tty layer ++static void port_sofrint(void *private) ++{ ++ struct usb_serial_port *port = (struct usb_serial_port *)private; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ struct tty_struct *tty = port->tty; ++ unsigned char *data = port->read_urb->transfer_buffer; ++ unsigned int UartNumber; ++ struct urb *urb = port->read_urb; ++ unsigned int RxCount = urb->actual_length; ++ int i, result; ++ int flag, flag_data; ++ ++ //UartNumber = MINOR(port->tty->device) - serial->minor; ++ UartNumber = tty->index - serial->minor; ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ mydbg ("%s - port->RxHolding = %d\n", __FUNCTION__, port->RxHolding); ++ ++ if (port_paranoia_check (port, __FUNCTION__) != 0) { ++ mydbg("%s - port_paranoia_check, exiting\n", __FUNCTION__); ++ port->ReadBulkStopped = 1; ++ return; ++ } ++ ++ if (!serial) { ++ mydbg("%s - bad serial pointer, exiting\n", __FUNCTION__); ++ return; ++ } ++ if (port->closePending == 1) //Were closing , stop reading ++ { ++ mydbg("%s - (port->closepending == 1\n", __FUNCTION__); ++ port->ReadBulkStopped = 1; ++ return; ++ } ++ ++ //RxHolding is asserted by throttle, if we assert it, we're not receiving any more ++ //characters and let the box handle the flow control ++ if (port->RxHolding == 1) { ++ port->ReadBulkStopped = 1; ++ return; ++ } ++ ++ if (urb->status) { ++ port->ReadBulkStopped = 1; ++ ++ mydbg("%s - nonzero read bulk status received: %d\n", __FUNCTION__, urb->status); ++ return; ++ } ++ ++ ++ tty = port->tty; ++ mydbg("%s - port %d, tty =0x%p\n", __FUNCTION__, port->number, tty); ++ ++ ++ if (tty && RxCount) { ++ flag_data = 0; ++ for (i = 0; i < RxCount ; ++i) { ++ //Look ahead code here ++ ++ if ((i <= (RxCount - 3)) && (THISCHAR == 0x1b) && (NEXTCHAR == 0x1b)) { ++ flag = 0; ++ switch (THIRDCHAR) { ++ case 0x00: ++ //Line status change 4th byte must follow ++ if (i > (RxCount - 4)) { ++ mydbg("Illegal escape sequences in received data\n"); ++ break; ++ } ++ ProcessLineStatus(port, FOURTHCHAR); ++ i += 3; ++ flag = 1; ++ break; ++ ++ case 0x01: ++ //Modem status status change 4th byte must follow ++ mydbg("Modem status status. \n"); ++ ++ if (i > (RxCount - 4)) { ++ mydbg("Illegal escape sequences in received data\n"); ++ break; ++ } ++ ProcessModemStatus(port, FOURTHCHAR); ++ i += 3; ++ flag = 1; ++ break; ++ case 0xff: ++ mydbg("No status sequence. \n"); ++ ++ ProcessRxChar(port, THISCHAR); ++ ProcessRxChar(port, NEXTCHAR); ++ i += 2; ++ break; ++ ++ }//end switch ++ if (flag == 1) ++ continue; ++ } //endif ++ ++ if(tty && urb->actual_length) { ++ tty_buffer_request_room(tty, 1); ++ tty_insert_flip_string(tty, (data + i), 1); ++ } ++ ++ ++ }//endfor ++ ++ tty_flip_buffer_push(tty); ++ ++ }//endif ++ ++ /* Continue trying to always read */ ++ usb_fill_bulk_urb (port->read_urb, serial->dev, ++ usb_rcvbulkpipe (serial->dev, ++ port->bulk_in_endpointAddress), ++ port->read_urb->transfer_buffer, ++ port->read_urb->transfer_buffer_length, ++ qt_read_bulk_callback, port); ++ result = usb_submit_urb(port->read_urb, GFP_ATOMIC); ++ if (result) ++ mydbg("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); ++ else ++ { ++ if (tty && RxCount) ++ flip_that(tty, UartNumber, serial); ++ } ++ ++ ++ return; ++ ++ } ++ ++ ++ ++static void qt_read_bulk_callback(struct urb *urb) ++{ ++ ++ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; ++ ++ ++ if (urb->status) ++ { ++ ++ port->ReadBulkStopped = 1; ++ mydbg("%s - nonzero write bulk status received: %d\n", __FUNCTION__, urb->status); ++ return; ++ } ++ ++ port_sofrint((void *) port); ++ schedule_work(&port->work); ++} ++ ++ ++static void ProcessRxChar(struct usb_serial_port *port, unsigned char Data){ ++ struct tty_struct *tty; ++ struct urb *urb = port->read_urb; ++ tty = port->tty; ++ /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ ++ ++ if(tty && urb->actual_length) ++ { ++ tty_buffer_request_room(tty, 1); ++ tty_insert_flip_string(tty, &Data, 1); ++ //tty_flip_buffer_push(tty); ++ ++ ++ } ++ ++ return; ++} ++ ++static void ProcessLineStatus(struct usb_serial_port *port, unsigned char line_status){ ++ ++ port->shadowLSR = line_status & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | ++ SERIAL_LSR_BI); ++ return; ++} ++ ++ ++static void ProcessModemStatus(struct usb_serial_port *port, unsigned char modem_status){ ++ ++ port->shadowMSR = modem_status; ++ wake_up_interruptible(&port->wait); ++ return; ++} ++ ++ ++ ++ ++ ++ ++static void serqt_usb_disconnect(struct usb_interface *interface){ ++ struct usb_serial *serial = usb_get_intfdata (interface); ++ //struct device *dev = &interface->dev; ++ struct usb_serial_port *port; ++ int i; ++ ++ mydbg ("%s\n", __FUNCTION__); ++ if (serial) ++ { ++ ++ serial->dev = NULL; ++ ++ for (i = 0; i < serial->num_ports; ++i) ++ serial->port[i].open_count = 0; ++ ++ for (i = 0; i < serial->num_bulk_in; ++i) ++ { ++ port = &serial->port[i]; ++ if (port->read_urb) ++ { ++ usb_unlink_urb (port->read_urb); ++ usb_free_urb (port->read_urb); ++ } ++ if (port->bulk_in_buffer) ++ kfree (port->bulk_in_buffer); ++ } ++ for (i = 0; i < serial->num_bulk_out; ++i) ++ { ++ port = &serial->port[i]; ++ if (port->write_urb) ++ { ++ usb_unlink_urb (port->write_urb); ++ usb_free_urb (port->write_urb); ++ } ++ if (port->bulk_out_buffer) ++ kfree (port->bulk_out_buffer); ++ } ++ for (i = 0; i < serial->num_interrupt_in; ++i) ++ { ++ port = &serial->port[i]; ++ if (port->interrupt_in_urb) ++ { ++ usb_unlink_urb (port->interrupt_in_urb); ++ usb_free_urb (port->interrupt_in_urb); ++ } ++ if (port->interrupt_in_buffer) ++ kfree (port->interrupt_in_buffer); ++ } ++ ++ ++ /* return the minor range that this device had */ ++ return_serial (serial); ++ ++ /* free up any memory that we allocated */ ++ kfree (serial); ++ ++ ++ ++ } else ++ { ++ info("device disconnected"); ++ } ++ ++ ++} ++ ++ ++ ++ ++ ++ ++ ++static struct usb_serial *get_serial_by_minor (unsigned int minor) ++{ ++ return serial_table[minor]; ++} ++ ++/***************************************************************************** ++ * Driver tty interface functions ++ *****************************************************************************/ ++static int serial_open (struct tty_struct *tty, struct file * filp){ ++ struct usb_serial *serial; ++ struct usb_serial_port *port; ++ unsigned int portNumber; ++ int retval = 0; ++ ++ mydbg("%s\n", __FUNCTION__); ++ ++ /* initialize the pointer incase something fails */ ++ tty->driver_data = NULL; ++ ++ /* get the serial object associated with this tty pointer */ ++ //serial = get_serial_by_minor (MINOR(tty->device)); ++ ++ /* get the serial object associated with this tty pointer */ ++ serial = get_serial_by_minor(tty->index); ++ ++ ++ if (serial_paranoia_check (serial, __FUNCTION__)) ++ return -ENODEV; ++ ++ ++ /* set up our port structure making the tty driver remember our port object, and us it */ ++ portNumber = tty->index - serial->minor; ++ port = &serial->port[portNumber]; ++ tty->driver_data = port; ++ ++ down (&port->sem); ++ port->tty = tty; ++ ++ ++ ++port->open_count; ++ if (port->open_count == 1) ++ { ++ port->closePending = 0; ++ mydbg("%s port->closepending = 0\n", __FUNCTION__); ++ ++ port->RxHolding = 0; ++ mydbg("%s port->RxHolding = 0\n", __FUNCTION__); ++ ++ retval = qt_open(port, filp); ++ } ++ ++ if (retval) ++ { ++ port->open_count = 0; ++ } ++ mydbg("%s returning port->closePending = %d\n", __FUNCTION__, port->closePending); ++ ++ up (&port->sem); ++ return retval; ++} ++/***************************************************************************** ++ *device's specific driver functions ++ *****************************************************************************/ ++static int qt_open (struct usb_serial_port *port, struct file *filp){ ++ struct usb_serial *serial = port->serial; ++ int result = 0; ++ unsigned int UartNumber; ++ struct qt_get_device_data DeviceData; ++ struct qt_open_channel_data ChannelData; ++ unsigned short default_divisor = 0x30; //gives 9600 baud rate ++ unsigned char default_LCR = SERIAL_8_DATA; // 8, none , 1 ++ int status = 0; ++ ++ ++ ++ ++ if (port_paranoia_check (port, __FUNCTION__)) ++ return -ENODEV; ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ /* force low_latency on so that our tty_push actually forces the data through, ++ otherwise it is scheduled, and with high data rates (like with OHCI) data ++ can get lost. */ ++ if (port->tty) ++ port->tty->low_latency = 0; ++ ++ ++ UartNumber = port->tty->index - serial->minor; ++ ++ status = box_get_device(serial, &DeviceData); ++ if (status < 0) ++ { ++ mydbg(__FILE__"box_get_device failed\n"); ++ return status; ++ } ++ serial->num_OpenCount++; ++ mydbg("%s serial->num_OpenCount = %d\n", __FUNCTION__, serial->num_OpenCount); ++ //Open uart channel ++ ++ //Port specific setups ++ status = BoxOPenCloseChannel(serial, UartNumber, 1, &ChannelData); ++ if (status < 0) ++ { ++ mydbg(__FILE__"BoxOPenCloseChannel failed\n"); ++ return status; ++ } ++ mydbg(__FILE__"BoxOPenCloseChannel completed.\n"); ++ ++ port->shadowLSR = ChannelData.line_status & ++ (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | SERIAL_LSR_BI); ++ ++ port->shadowMSR = ChannelData.modem_status & ++ (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_CD); ++ ++ ++ //Set Baud rate to default and turn off (default)flow control here ++ status = BoxSetUart(serial, UartNumber, default_divisor, default_LCR); ++ if (status < 0) ++ { ++ mydbg(__FILE__"BoxSetUart failed\n"); ++ return status; ++ } ++ mydbg(__FILE__"BoxSetUart completed.\n"); ++ ++ ++ //Put this here to make it responsive to stty and defauls set by the tty layer ++ qt_set_termios(port, NULL); ++ ++ ++ //Initialize the wait que head ++ init_waitqueue_head(&(port->wait)); ++ ++ /* if we have a bulk endpoint, start reading from it */ ++ if (serial->num_bulk_in) ++ { ++ /* Start reading from the device */ ++ usb_fill_bulk_urb (port->read_urb, serial->dev, ++ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), ++ port->read_urb->transfer_buffer, ++ port->read_urb->transfer_buffer_length, ++ qt_read_bulk_callback, ++ port); ++ ++ port->ReadBulkStopped = 0; ++ ++ result = usb_submit_urb(port->read_urb, GFP_ATOMIC); ++ ++ if (result) ++ { ++ err("%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); ++ port->ReadBulkStopped = 1; ++ } ++ ++ } ++ ++ return result; ++} ++ ++static void serial_close(struct tty_struct *tty, struct file * filp){ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ ++ if (!serial) ++ return; ++ ++ down (&port->sem); ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ /* if disconnect beat us to the punch here, there's nothing to do */ ++ if (tty->driver_data) ++ { ++ if (!port->open_count) ++ { ++ mydbg ("%s - port not opened\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ --port->open_count; ++ if (port->open_count <= 0) ++ { ++ port->closePending = 1; ++ mydbg ("%s - port->closePending = 1\n", __FUNCTION__); ++ ++ if (serial->dev) ++ { ++ qt_close(port, filp); ++ port->open_count = 0; ++ } ++ } ++ ++ } ++ ++ exit: ++ up (&port->sem); ++ ++ mydbg("%s - %d return\n", __FUNCTION__, port->number); ++ ++ ++} ++ ++static void qt_close (struct usb_serial_port *port, struct file *filp){ ++ unsigned long jift = jiffies + 10 * HZ; ++ __u8 LSR_Value, MCR_Value; ++ struct usb_serial *serial = port->serial; ++ int status; ++ unsigned int UartNumber; ++ ++ struct qt_open_channel_data ChannelData; ++ status = 0; ++ LSR_Value = 0; ++ ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ UartNumber = port->tty->index - serial->minor; ++ ++ /* shutdown any bulk reads that might be going on */ ++ if (serial->num_bulk_out) ++ usb_unlink_urb (port->write_urb); ++ if (serial->num_bulk_in) ++ usb_unlink_urb (port->read_urb); ++ ++ ++ //wait up to 30 seconds for transmitter to empty ++ do ++ { ++ status = BoxGetRegister(serial, UartNumber, LINE_STATUS_REGISTER, &LSR_Value); ++ if (status < 0) ++ { ++ mydbg(__FILE__"box_get_device failed\n"); ++ break; ++ } ++ ++ if ((LSR_Value & SERIAL_LSR_TEMT) && (port->ReadBulkStopped == 1)) ++ break; ++ schedule(); ++ ++ ++ } ++ while (jiffies <= jift); ++ ++ if(jiffies > jift) ++ mydbg("%s - port %d timout of checking transmitter empty\n", __FUNCTION__, port->number); ++ else ++ mydbg("%s - port %d checking transmitter empty succeded\n", __FUNCTION__, port->number); ++ ++ ++ ++ status = BoxGetRegister(serial, UartNumber, MODEM_CONTROL_REGISTER, &MCR_Value); ++ mydbg(__FILE__"BoxGetRegister MCR = 0x%x.\n", MCR_Value); ++ ++ ++ if (status >= 0) ++ { ++ MCR_Value &= ~(SERIAL_MCR_DTR | SERIAL_MCR_RTS); ++// status = BoxSetRegister(serial, UartNumber, MODEM_CONTROL_REGISTER, MCR_Value); ++ } ++ ++ ++ //Close uart channel ++ status = BoxOPenCloseChannel(serial, UartNumber, 0, &ChannelData); ++ if(status < 0) ++ mydbg("%s - port %d BoxOPenCloseChannel failed.\n", __FUNCTION__, port->number); ++ ++ serial->num_OpenCount--; ++ ++ ++} ++ ++ ++ ++static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) ++{ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ struct usb_serial *serial; ++ int retval = -EINVAL; ++ unsigned int UartNumber; ++ int from_user = 0; ++ ++ ++ serial = get_usb_serial (port, __FUNCTION__); ++ if(serial == NULL) ++ return -ENODEV; ++ //This can happen if we get disconnected a ++ if (port->open_count == 0) ++ { ++ return -ENODEV; ++ } ++ UartNumber = port->tty->index - serial->minor; ++ ++ mydbg("%s - port %d, %d byte(s)\n", __FUNCTION__, port->number, count); ++ mydbg("%s - port->RxHolding = %d\n", __FUNCTION__, port->RxHolding); ++ ++ if (!port->open_count) ++ { ++ mydbg("%s - port not opened\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ retval = qt_write(port, from_user, buf, count); ++ ++ exit: ++ return retval; ++} ++ ++ ++static int qt_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count){ ++ int result; ++ unsigned int UartNumber; ++ ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ if(serial == NULL) ++ return -ENODEV; ++ ++ ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ if (count == 0) ++ { ++ mydbg("%s - write request of 0 bytes\n", __FUNCTION__); ++ return(0); ++ } ++ ++ ++ UartNumber = port->tty->index - serial->minor; ++ /* only do something if we have a bulk out endpoint */ ++ if (serial->num_bulk_out) ++ { ++ if (port->write_urb->status == -EINPROGRESS) ++ { ++ mydbg("%s - already writing\n", __FUNCTION__); ++ return(0); ++ } ++ ++ count = (count > port->bulk_out_size) ? port->bulk_out_size : count; ++ ++ if (from_user) ++ { ++ if (copy_from_user(port->write_urb->transfer_buffer, buf, count)) ++ return -EFAULT; ++ } else ++ { ++ memcpy (port->write_urb->transfer_buffer, buf, count); ++ } ++ ++ //usb_serial_debug_data(__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); ++ ++ /* set up our urb */ ++ ++ ++ usb_fill_bulk_urb (port->write_urb, serial->dev, ++ usb_sndbulkpipe (serial->dev, ++ port->bulk_out_endpointAddress), ++ port->write_urb->transfer_buffer, count, ++ qt_write_bulk_callback, port); ++ ++ ++ ++ ++ ++ /* send the data out the bulk port */ ++ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); ++ if (result) ++ mydbg("%s - failed submitting write urb, error %d\n", __FUNCTION__, result); ++ else ++ result = count; ++ ++ return result; ++ } ++ ++ /* no bulk out, so return 0 bytes written */ ++ return(0); ++} ++ ++ ++ ++static void qt_write_bulk_callback(struct urb *urb) ++{ ++ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ if (!serial) ++ { ++ mydbg("%s - bad serial pointer, exiting\n", __FUNCTION__); ++ return; ++ } ++ ++ if (urb->status) ++ { ++ mydbg("%s - nonzero write bulk status received: %d\n", __FUNCTION__, urb->status); ++ return; ++ } ++ // ++ port_softint(&port->work); ++ schedule_work(&port->work); ++ ++ return; ++} ++ ++ ++static void port_softint(struct work_struct *work) ++{ ++ struct usb_serial_port *port = ++ container_of(work, struct usb_serial_port, work); ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ struct tty_struct *tty; ++ ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ ++ ++ if (!serial) ++ return; ++ ++ ++ tty = port->tty; ++ if (!tty) ++ return; ++ ++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) ++ { ++ mydbg("%s - write wakeup call.\n", __FUNCTION__); ++ (tty->ldisc.write_wakeup)(tty); ++ } ++ ++ wake_up_interruptible(&tty->write_wait); ++} ++static int serial_write_room (struct tty_struct *tty) ++{ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ int retval = -EINVAL; ++ ++ if (!serial) ++ return -ENODEV; ++ ++ down (&port->sem); ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ if (!port->open_count) ++ { ++ mydbg("%s - port not open\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ retval = qt_write_room(port); ++ ++ exit: ++ up (&port->sem); ++ return retval; ++} ++static int qt_write_room (struct usb_serial_port *port) ++{ ++ struct usb_serial *serial = port->serial; ++ int room = 0; ++ if (port->closePending == 1) ++ { ++ mydbg("%s - port->closePending == 1\n", __FUNCTION__); ++ return -ENODEV; ++ } ++ ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ if (serial->num_bulk_out) ++ { ++ if (port->write_urb->status != -EINPROGRESS) ++ room = port->bulk_out_size; ++ } ++ ++ mydbg("%s - returns %d\n", __FUNCTION__, room); ++ return(room); ++} ++static int serial_chars_in_buffer (struct tty_struct *tty) ++{ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ int retval = -EINVAL; ++ ++ if (!serial) ++ return -ENODEV; ++ ++ down (&port->sem); ++ ++ mydbg("%s = port %d\n", __FUNCTION__, port->number); ++ ++ if (!port->open_count) { ++ mydbg("%s - port not open\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ retval = qt_chars_in_buffer(port); ++ ++exit: ++ up (&port->sem); ++ return retval; ++} ++ ++ ++ ++static int qt_chars_in_buffer (struct usb_serial_port *port) ++{ ++ struct usb_serial *serial = port->serial; ++ int chars = 0; ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ if (serial->num_bulk_out) ++ { ++ if (port->write_urb->status == -EINPROGRESS) ++ chars = port->write_urb->transfer_buffer_length; ++ } ++ ++ mydbg("%s - returns %d\n", __FUNCTION__, chars); ++ return(chars); ++} ++ ++ ++static int serial_tiocmset (struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) ++{ ++ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ int retval = -ENODEV; ++ unsigned int UartNumber; ++ mydbg("In %s \n", __FUNCTION__); ++ ++ if (!serial) ++ return -ENODEV; ++ ++ ++ UartNumber = port->tty->index - serial->minor; ++ ++ ++ down (&port->sem); ++ ++ mydbg("%s - port %d \n", __FUNCTION__, port->number); ++ mydbg ("%s - port->RxHolding = %d\n", __FUNCTION__, port->RxHolding); ++ ++ if (!port->open_count) ++ { ++ mydbg ("%s - port not open\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ retval = qt_tiocmset(port, file, set); ++ ++ exit: ++ up (&port->sem); ++ return retval; ++} ++ ++ ++static int qt_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int value) ++{ ++ ++ __u8 MCR_Value; ++ int status; ++ unsigned int UartNumber; ++ ++ ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ if(serial == NULL) ++ return -ENODEV; ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ /**************************************************************************************/ ++ /** TIOCMGET ++ */ ++ UartNumber = port->tty->index - serial->minor; ++ status = BoxGetRegister(port->serial, UartNumber, MODEM_CONTROL_REGISTER, &MCR_Value); ++ if (status < 0) ++ return -ESPIPE; ++ ++ //Turn off the RTS and DTR and loopbcck and then only ++ //trun on what was asked for ++ MCR_Value &= ~(SERIAL_MCR_RTS | SERIAL_MCR_DTR | SERIAL_MCR_LOOP); ++ if (value & TIOCM_RTS) ++ MCR_Value |= SERIAL_MCR_RTS; ++ if (value & TIOCM_DTR) ++ MCR_Value |= SERIAL_MCR_DTR; ++ if (value & TIOCM_LOOP) ++ MCR_Value |= SERIAL_MCR_LOOP; ++ ++ status = BoxSetRegister(port->serial, UartNumber, MODEM_CONTROL_REGISTER, MCR_Value); ++ if (status < 0) ++ return -ESPIPE; ++ else ++ return 0; ++} ++ ++static int serial_tiocmget(struct tty_struct *tty, struct file *file) ++{ ++ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ int retval = -ENODEV; ++ unsigned int UartNumber; ++ mydbg("In %s \n", __FUNCTION__); ++ ++ if (!serial) ++ return -ENODEV; ++ ++ ++ UartNumber = port->tty->index - serial->minor; ++ ++ ++ down (&port->sem); ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ mydbg ("%s - port->RxHolding = %d\n", __FUNCTION__, port->RxHolding); ++ ++ if (!port->open_count) ++ { ++ mydbg ("%s - port not open\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ retval = qt_tiocmget(port, file); ++ ++ exit: ++ up (&port->sem); ++ return retval; ++} ++ ++ ++ ++static int qt_tiocmget(struct usb_serial_port *port, struct file * file) ++{ ++ ++ __u8 MCR_Value; ++ __u8 MSR_Value; ++ unsigned int result = 0; ++ int status; ++ unsigned int UartNumber; ++ struct tty_struct * tty; ++ ++ ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ if(serial == NULL) ++ return -ENODEV; ++ tty = port->tty; ++ ++ mydbg("%s - port %d, tty =0x%p\n", __FUNCTION__, port->number, tty); ++ ++ /**************************************************************************************/ ++ /** TIOCMGET ++ */ ++ UartNumber = port->tty->index - serial->minor; ++ status = BoxGetRegister(port->serial, UartNumber, MODEM_CONTROL_REGISTER, &MCR_Value); ++ if (status >= 0) ++ { ++ status = BoxGetRegister(port->serial, UartNumber, MODEM_STATUS_REGISTER, &MSR_Value); ++ ++ } ++ ++ if (status >= 0) ++ { ++ result = ((MCR_Value & SERIAL_MCR_DTR) ? TIOCM_DTR: 0) ++ //DTR IS SET ++ | ((MCR_Value & SERIAL_MCR_RTS) ? TIOCM_RTS: 0) ++ //RTS IS SET ++ | ((MSR_Value & SERIAL_MSR_CTS) ? TIOCM_CTS: 0) ++ //CTS is set ++ | ((MSR_Value & SERIAL_MSR_CD) ? TIOCM_CAR: 0) ++ //Carrier detect is set ++ | ((MSR_Value & SERIAL_MSR_RI) ? TIOCM_RI: 0) ++ //Ring indicator set ++ | ((MSR_Value & SERIAL_MSR_DSR) ? TIOCM_DSR: 0); ++ //DSR is set ++ return result; ++ ++ } ++ else ++ return -ESPIPE; ++ //endif tatus => 0 ++} ++ ++ ++ ++static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) ++{ ++ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ int retval = -ENODEV; ++ unsigned int UartNumber; ++ mydbg("In %s \n", __FUNCTION__); ++ ++ if (!serial) ++ return -ENODEV; ++ ++ ++ UartNumber = port->tty->index - serial->minor; ++ ++ ++ down (&port->sem); ++ ++ mydbg("%s - port %d, cmd 0x%.4x\n", __FUNCTION__, port->number, cmd); ++ mydbg ("%s - port->RxHolding = %d\n", __FUNCTION__, port->RxHolding); ++ ++ if (!port->open_count) ++ { ++ mydbg ("%s - port not open\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ retval = qt_ioctl(port, file, cmd, arg); ++ ++ exit: ++ up (&port->sem); ++ return retval; ++} ++static int qt_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) ++{ ++ __u8 MCR_Value; ++ __u8 MSR_Value; ++ unsigned short Prev_MSR_Value; ++ unsigned int value, result = 0; ++ int status; ++ unsigned int UartNumber; ++ struct tty_struct * tty; ++ ++ ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ if(serial == NULL) ++ return -ENODEV; ++ tty = port->tty; ++ ++ mydbg("%s - port %d, tty =0x%p\n", __FUNCTION__, port->number, tty); ++ ++ /**************************************************************************************/ ++ /** TIOCMGET ++ */ ++ UartNumber = port->tty->index - serial->minor; ++ ++ if(cmd == TIOCMGET) ++ { ++ MCR_Value = port->shadowMCR; ++ MSR_Value = port->shadowMSR; ++ ++ { ++ result = ((MCR_Value & SERIAL_MCR_DTR) ? TIOCM_DTR: 0) ++ //DTR IS SET ++ | ((MCR_Value & SERIAL_MCR_RTS) ? TIOCM_RTS: 0) ++ //RTS IS SET ++ | ((MSR_Value & SERIAL_MSR_CTS) ? TIOCM_CTS: 0) ++ //CTS is set ++ | ((MSR_Value & SERIAL_MSR_CD) ? TIOCM_CAR: 0) ++ //Carrier detect is set ++ | ((MSR_Value & SERIAL_MSR_RI) ? TIOCM_RI: 0) ++ //Ring indicator set ++ | ((MSR_Value & SERIAL_MSR_DSR) ? TIOCM_DSR: 0); ++ //DSR is set ++ if(copy_to_user((unsigned int *)arg, &result, sizeof(unsigned int))) ++ return -EFAULT; ++ return 0; ++ ++ }//endif tatus => 0 ++ ++ }//endif(cmd == TIOCMGET) ++ /**************************************************************************************/ ++ /** End TIOCMGET ++ */ ++ /**************************************************************************************/ ++ /** TIOCMBIS, TIOCMBIC, AND TIOCMSET */ ++ ++ /**************************************************************************************/ ++ ++ if(cmd == TIOCMBIS || cmd == TIOCMBIC || cmd == TIOCMSET) ++ { ++ status = BoxGetRegister(port->serial, UartNumber, MODEM_CONTROL_REGISTER, &MCR_Value); ++ if (status < 0) ++ return -ESPIPE; ++ if (copy_from_user(&value, (unsigned int *)arg, sizeof(unsigned int))) ++ return -EFAULT; ++ ++ switch (cmd) ++ { ++ case TIOCMBIS: ++ if (value & TIOCM_RTS) ++ MCR_Value |= SERIAL_MCR_RTS; ++ if (value & TIOCM_DTR) ++ MCR_Value |= SERIAL_MCR_DTR; ++ if (value & TIOCM_LOOP) ++ MCR_Value |= SERIAL_MCR_LOOP; ++ break; ++ case TIOCMBIC: ++ if (value & TIOCM_RTS) ++ MCR_Value &= ~SERIAL_MCR_RTS; ++ if (value & TIOCM_DTR) ++ MCR_Value &= ~SERIAL_MCR_DTR; ++ if (value & TIOCM_LOOP) ++ MCR_Value &= ~SERIAL_MCR_LOOP; ++ break; ++ case TIOCMSET: ++ //Turn off the RTS and DTR and loopbcck and then only ++ //trun on what was asked for ++ MCR_Value &= ~(SERIAL_MCR_RTS | SERIAL_MCR_DTR | SERIAL_MCR_LOOP); ++ if (value & TIOCM_RTS) ++ MCR_Value |= SERIAL_MCR_RTS; ++ if (value & TIOCM_DTR) ++ MCR_Value |= SERIAL_MCR_DTR; ++ if (value & TIOCM_LOOP) ++ MCR_Value |= SERIAL_MCR_LOOP; ++ break; ++ default: ++ break; ++ ++ } ++ status = BoxSetRegister(port->serial, UartNumber, MODEM_CONTROL_REGISTER, MCR_Value); ++ if (status < 0) ++ return -ESPIPE; ++ else ++ { ++ port->shadowMCR = MCR_Value; ++ return 0; ++ } ++ ++ ++ } ++ /**************************************************************************************/ ++ /** TIOCMBIS, TIOCMBIC, AND TIOCMSET end ++ */ ++ /**************************************************************************************/ ++ ++ if(cmd == TIOCMIWAIT) ++ { ++ DECLARE_WAITQUEUE(wait, current); ++ Prev_MSR_Value = port->shadowMSR & SERIAL_MSR_MASK; ++ while(1) ++ { ++ add_wait_queue(&port->wait, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); ++ remove_wait_queue(&port->wait, &wait); ++ /* see if a signal woke us up */ ++ if(signal_pending(current)) ++ return -ERESTARTSYS; ++ MSR_Value = port->shadowMSR & SERIAL_MSR_MASK; ++ if(MSR_Value == Prev_MSR_Value) ++ return -EIO; //no change error ++ ++ if((arg & TIOCM_RNG && ((Prev_MSR_Value & SERIAL_MSR_RI) == ++ (MSR_Value & SERIAL_MSR_RI))) || ++ (arg & TIOCM_DSR && ((Prev_MSR_Value & SERIAL_MSR_DSR) == ++ (MSR_Value & SERIAL_MSR_DSR))) || ++ (arg & TIOCM_CD && ((Prev_MSR_Value & SERIAL_MSR_CD) == ++ (MSR_Value & SERIAL_MSR_CD))) || ++ (arg & TIOCM_CTS && ((Prev_MSR_Value & SERIAL_MSR_CTS) == ++ (MSR_Value & SERIAL_MSR_CTS)))) ++ { ++ return 0; ++ } ++ ++ }//endwhile ++ ++ } ++ mydbg("%s -No ioctl for that one. port = %d\n", __FUNCTION__, port->number); ++ ++ ++ return -ENOIOCTLCMD; ++} ++ ++static void serial_set_termios (struct tty_struct *tty, struct ktermios *old) ++{ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ ++ if (!serial) ++ return; ++ ++ down (&port->sem); ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ if (!port->open_count) { ++ mydbg("%s - port not open\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ /* pass on to the driver specific version of this function if it is available */ ++ qt_set_termios(port, old); ++ ++exit: ++ up (&port->sem); ++} ++ ++static void qt_set_termios(struct usb_serial_port *port, struct ktermios *old_termios) ++{ ++ unsigned int cflag; ++ int baud, divisor, remainder; ++ unsigned char LCR_change_to = 0; ++ struct tty_struct *tty; ++ int status; ++ struct usb_serial *serial; ++ __u16 UartNumber; ++ __u16 tmp, tmp2; ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ tmp = port->tty->index; ++ mydbg("%s - MINOR(port->tty->index) = %d\n", __FUNCTION__, tmp); ++ ++ ++ serial = port->serial; ++ tmp2 = serial->minor; ++ mydbg("%s - serial->minor = %d\n", __FUNCTION__, tmp2); ++ ++ ++ ++ UartNumber = port->tty->index - serial->minor; ++ ++ tty = port->tty; ++ ++ cflag = tty->termios->c_cflag; ++ ++ if (old_termios) ++ { ++ if((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(tty->termios->c_iflag) == ++ RELEVANT_IFLAG(old_termios->c_iflag))) ++ { ++ mydbg("%s - Nothing to change\n", __FUNCTION__); ++ return; ++ } ++ ++ ++ } ++ ++ mydbg("%s - 3\n", __FUNCTION__); ++ ++ switch(cflag) ++ { ++ case CS5: ++ LCR_change_to |= SERIAL_5_DATA; ++ break; ++ case CS6: ++ LCR_change_to |= SERIAL_6_DATA; ++ break; ++ case CS7: ++ LCR_change_to |= SERIAL_7_DATA; ++ break; ++ default: ++ case CS8: ++ LCR_change_to |= SERIAL_8_DATA; ++ break; ++ } ++ ++ //Parity stuff ++ if(cflag & PARENB) ++ { ++ if(cflag & PARODD) ++ LCR_change_to |= SERIAL_ODD_PARITY; ++ else ++ LCR_change_to |= SERIAL_EVEN_PARITY; ++ } ++ if(cflag & CSTOPB) ++ LCR_change_to |= SERIAL_TWO_STOPB; ++ else ++ LCR_change_to |= SERIAL_TWO_STOPB; ++ ++ mydbg("%s - 4\n", __FUNCTION__); ++ //Thats the LCR stuff, go ahead and set it ++ baud = tty_get_baud_rate(tty); ++ if (!baud) { ++ /* pick a default, any default... */ ++ baud = 9600; ++ } ++ ++ mydbg("%s - got baud = %d\n", __FUNCTION__, baud); ++ ++ ++ divisor = MAX_BAUD_RATE / baud; ++ remainder = MAX_BAUD_RATE % baud; ++ //Round to nearest divisor ++ if(((remainder * 2) >= baud) && (baud != 110)) ++ divisor++; ++ ++ //Set Baud rate to default and turn off (default)flow control here ++ status = BoxSetUart(serial, UartNumber, (unsigned short) divisor, LCR_change_to); ++ if (status < 0) ++ { ++ mydbg(__FILE__"BoxSetUart failed\n"); ++ return; ++ } ++ //************************Now determine flow control ++ ++ if(cflag & CRTSCTS) ++ { ++ mydbg("%s - Enabling HW flow control port %d\n", __FUNCTION__, port->number); ++ ++ //Enable RTS/CTS flow control ++ status = BoxSetHW_FlowCtrl(serial, UartNumber, 1); ++ ++ if (status < 0) ++ { ++ mydbg(__FILE__"BoxSetHW_FlowCtrl failed\n"); ++ return; ++ } ++ } ++ else ++ { ++ //Disable RTS/CTS flow control ++ mydbg("%s - disabling HW flow control port %d\n", __FUNCTION__, port->number); ++ ++ status = BoxSetHW_FlowCtrl(serial, UartNumber, 0); ++ if (status < 0) ++ { ++ mydbg(__FILE__"BoxSetHW_FlowCtrl failed\n"); ++ return; ++ } ++ ++ ++ } ++ ++ //************************************************* ++ /* if we are implementing XON/XOFF, set the start and stop character in the device */ ++ if (I_IXOFF(tty) || I_IXON(tty)) ++ { ++ unsigned char stop_char = STOP_CHAR(tty); ++ unsigned char start_char = START_CHAR(tty); ++ status = BoxSetSW_FlowCtrl(serial, UartNumber, stop_char, start_char); ++ if(status < 0) ++ mydbg(__FILE__"BoxSetSW_FlowCtrl (enabled) failed\n"); ++ ++ } ++ else ++ { ++ //disable SW flow control ++ status = BoxDisable_SW_FlowCtrl(serial, UartNumber); ++ if(status < 0) ++ mydbg(__FILE__"BoxSetSW_FlowCtrl (diabling) failed\n"); ++ ++ } ++ ++ ++ ++} ++/**************************************************************************** ++* BoxGetRegister ++* issuse a GET_REGISTER vendor-spcific request on the default control pipe ++* If successful, fills in the pValue with the register value asked for ++****************************************************************************/ ++static int BoxGetRegister(struct usb_serial *serial, unsigned short Uart_Number, ++ unsigned short Register_Num, __u8 *pValue ) ++{ ++ int result; ++ __u16 current_length; ++ ++ ++ current_length = sizeof(struct qt_get_device_data); ++ ++ result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), QT_GET_SET_REGISTER, ++ 0xC0, Register_Num, Uart_Number, (void *)pValue, sizeof(*pValue), 300); ++ ++ return result; ++} ++/**************************************************************************** ++* BoxSetRegister ++* issuse a GET_REGISTER vendor-spcific request on the default control pipe ++* If successful, fills in the pValue with the register value asked for ++****************************************************************************/ ++static int BoxSetRegister(struct usb_serial *serial, unsigned short Uart_Number, ++ unsigned short Register_Num, unsigned short Value ) ++{ ++ int result; ++ unsigned short RegAndByte; ++ ++ ++ RegAndByte = Value; ++ RegAndByte = RegAndByte << 8; ++ RegAndByte = RegAndByte + Register_Num; ++ ++// result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_GET_SET_REGISTER, ++// 0xC0, Register_Num, Uart_Number, NULL, 0, 300); ++ ++ ++ result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_GET_SET_REGISTER, ++ 0x40, RegAndByte, Uart_Number, NULL,0, 300); ++ ++ ++ return result; ++} ++ ++ ++ ++/** ++ * box_get_device ++ * Issue a GET_DEVICE vendor-specific request on the default control pipe If ++ * successful, fills in the qt_get_device_data structure pointed to by ++ * device_data, otherwise return a negative error number of the problem. ++ */ ++static int box_get_device(struct usb_serial *serial, ++ struct qt_get_device_data *device_data) ++{ ++ int result; ++ __u16 current_length; ++ unsigned char *transfer_buffer; ++ ++ current_length = sizeof(struct qt_get_device_data); ++ transfer_buffer = kmalloc(current_length, GFP_KERNEL); ++ if (!transfer_buffer) ++ return -ENOMEM; ++ ++ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), ++ QT_SET_GET_DEVICE, 0xc0, 0, 0, ++ transfer_buffer, current_length, 300); ++ if (result > 0) ++ memcpy(device_data, transfer_buffer, current_length); ++ kfree(transfer_buffer); ++ ++ return result; ++} ++ ++/** ++ * box_set_device ++ * Issue a SET_DEVICE vendor-specific request on the default control pipe If ++ * successful returns the number of bytes written, otherwise it returns a ++ * negative error number of the problem. ++ */ ++static int box_set_device(struct usb_serial *serial, struct qt_get_device_data *device_data) ++{ ++ int result; ++ __u16 length; ++ __u16 PortSettings; ++ ++ PortSettings = ((__u16)(device_data->portb)); ++ PortSettings = (PortSettings << 8); ++ PortSettings += ((__u16)(device_data->porta)); ++ ++ length = sizeof(struct qt_get_device_data); ++ mydbg("%s - PortSettings = 0x%x\n", __FUNCTION__, PortSettings); ++ ++ result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), ++ QT_SET_GET_DEVICE, 0x40, PortSettings, ++ 0, NULL, 0, 300); ++ return result; ++} ++ ++/**************************************************************************** ++ * BoxOPenCloseChannel ++ * This funciotn notifies the device that the device driver wishes to open a particular UART channel. its ++ * purpose is to allow the device driver and the device to synchronize state information. ++ * OpenClose = 1 for open , 0 for close ++ ****************************************************************************/ ++static int BoxOPenCloseChannel(struct usb_serial *serial, __u16 Uart_Number, __u16 OpenClose, struct qt_open_channel_data *pDeviceData) ++{ ++ int result; ++ __u16 length; ++ __u8 Direcion; ++ unsigned int pipe; ++ length = sizeof(struct qt_open_channel_data); ++ ++ if (OpenClose == 1) //IF OPENING ++ { ++ Direcion = USBD_TRANSFER_DIRECTION_IN; ++ pipe = usb_rcvctrlpipe(serial->dev, 0); ++ result = usb_control_msg (serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL, ++ Direcion, OpenClose, Uart_Number, pDeviceData, length, 300); ++ ++ ++ } ++ else ++ { ++ Direcion = USBD_TRANSFER_DIRECTION_OUT; ++ pipe = usb_sndctrlpipe(serial->dev, 0); ++ result = usb_control_msg (serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL, ++ Direcion, OpenClose, Uart_Number, NULL, 0, 300); ++ ++ } ++ ++ ++ ++ return result; ++} ++ ++/**************************************************************************** ++ * BoxSetPrebufferLevel ++ TELLS BOX WHEN TO ASSERT FLOW CONTROL ++ ****************************************************************************/ ++static int BoxSetPrebufferLevel(struct usb_serial *serial) ++{ ++ int result; ++ __u16 buffer_length; ++ ++ buffer_length = PREFUFF_LEVEL_CONSERVATIVE; ++ result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), ++ QT_GET_SET_PREBUF_TRIG_LVL, 0x40, ++ buffer_length, 0, NULL, 0, 300); ++ return result; ++} ++ ++ ++ ++/**************************************************************************** ++ * BoxSetATC ++ TELLS BOX WHEN TO ASSERT automatic transmitter control ++ ****************************************************************************/ ++static int BoxSetATC(struct usb_serial *serial, __u16 n_Mode) ++{ ++ int result; ++ __u16 buffer_length; ++ ++ ++ buffer_length = PREFUFF_LEVEL_CONSERVATIVE; ++ ++ result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_SET_ATF, ++ 0x40, n_Mode, 0, NULL, 0, 300); ++ ++ return result; ++} ++ ++/**************************************************************************** ++* BoxSetUart ++* issuse a SET_UART vendor-spcific request on the default control pipe ++* If successful sets baud rate divisor and LCR value ++****************************************************************************/ ++static int BoxSetUart(struct usb_serial *serial, unsigned short Uart_Number, ++ unsigned short default_divisor, unsigned char default_LCR ) ++{ ++ int result; ++ unsigned short UartNumandLCR; ++ ++ UartNumandLCR = (default_LCR << 8) + Uart_Number; ++ ++ result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_GET_SET_UART, ++ 0x40, default_divisor, UartNumandLCR, NULL, 0, 300); ++ ++ return result; ++} ++ ++ ++static int BoxSetHW_FlowCtrl(struct usb_serial *serial, unsigned int UartNumber, int bSet) ++{ ++ __u8 MCR_Value = 0; ++ __u8 MSR_Value = 0, MOUT_Value = 0; ++ struct usb_serial_port *port; ++ unsigned int status; ++ ++ port = serial->port; ++ ++ if (bSet == 1) ++ { ++ MCR_Value = SERIAL_MCR_RTS; //flow control, box will clear RTS line to prevent remote ++ } //device from xmitting more chars ++ else ++ { //no flow control to remote device ++ MCR_Value = 0; ++ ++ } ++ MOUT_Value = MCR_Value << 8; ++ ++ ++ if(bSet == 1) ++ { ++ MSR_Value = SERIAL_MSR_CTS; //flow control, box will inhibit xmit data if CTS line is asserted ++ } ++ else ++ { ++ MSR_Value = 0; //Box will not inhimbe xmit data due to CTS line ++ } ++ MOUT_Value |= MSR_Value; ++ ++ ++ status = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_HW_FLOW_CONTROL_MASK, ++ 0x40, MOUT_Value, UartNumber, NULL, 0, 300); ++ return status; ++ ++} ++ ++static int BoxSetSW_FlowCtrl(struct usb_serial *serial, __u16 UartNumber, unsigned char stop_char, unsigned char start_char) ++{ ++ __u16 nSWflowout; ++ int result; ++ ++ nSWflowout = start_char << 8; ++ nSWflowout = (unsigned short)stop_char; ++ ++ result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_SW_FLOW_CONTROL_MASK, ++ 0x40, nSWflowout, UartNumber, NULL, 0, 300); ++ return result; ++ ++} ++static int BoxDisable_SW_FlowCtrl(struct usb_serial *serial, __u16 UartNumber) ++{ ++ int result; ++ ++ ++ result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_SW_FLOW_CONTROL_DISABLE, ++ 0x40, 0, UartNumber, NULL, 0, 300); ++ return result; ++ ++} ++ ++ ++/***************************************************************************** ++ * SerialThrottle ++ * this function is called by the tty driver when it wants to stop the data ++ * being read from the port. ++ *****************************************************************************/ ++ ++ ++static void serial_throttle (struct tty_struct * tty) ++{ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ if (!serial) ++ return; ++ ++ down (&port->sem); ++ ++ ++ if (!port->open_count) { ++ mydbg ("%s - port not open\n", __FUNCTION__); ++ goto exit; ++ } ++ //shut down any bulk reads that may be going on ++// usb_unlink_urb (port->read_urb); ++ /* pass on to the driver specific version of this function */ ++ port->RxHolding = 1; ++ mydbg("%s - port->RxHolding = 1\n", __FUNCTION__); ++ ++ ++exit: ++ up (&port->sem); ++ return; ++} ++ ++static void serial_unthrottle (struct tty_struct * tty) ++{ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ unsigned int result; ++ ++ if (!serial) ++ return; ++ down (&port->sem); ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ if (!port->open_count) { ++ mydbg ("%s - port not open\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ if(port->RxHolding == 1) ++ { ++ mydbg ("%s -port->RxHolding == 1\n", __FUNCTION__); ++ ++ port->RxHolding = 0; ++ mydbg ("%s - port->RxHolding = 0\n", __FUNCTION__); ++ ++ /* if we have a bulk endpoint, start it up */ ++ if ((serial->num_bulk_in) && (port->ReadBulkStopped == 1)) ++ { ++ /* Start reading from the device */ ++ usb_fill_bulk_urb (port->read_urb, serial->dev, ++ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), ++ port->read_urb->transfer_buffer, ++ port->read_urb->transfer_buffer_length, ++ qt_read_bulk_callback, ++ port); ++ result = usb_submit_urb(port->read_urb, GFP_ATOMIC); ++ if (result) ++ err("%s - failed restarting read urb, error %d", __FUNCTION__, result); ++ } ++ } ++ exit: ++ up (&port->sem); ++ return; ++ ++ ++ ++} ++ ++ ++static void serial_break (struct tty_struct *tty, int break_state) ++{ ++ struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data; ++ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); ++ __u16 UartNumber, Break_Value; ++ unsigned int result; ++ ++ UartNumber = port->tty->index - serial->minor; ++ if (!serial) ++ return; ++ ++ if(break_state == -1) ++ Break_Value = 1; ++ else ++ Break_Value = 0; ++ ++ down (&port->sem); ++ ++ mydbg("%s - port %d\n", __FUNCTION__, port->number); ++ ++ if (!port->open_count) { ++ mydbg("%s - port not open\n", __FUNCTION__); ++ goto exit; ++ } ++ ++ result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), QT_BREAK_CONTROL, ++ 0x40, Break_Value, UartNumber, NULL, 0, 300); ++ ++exit: ++ up (&port->sem); ++} ++ ++ ++ ++ ++static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) ++{ ++ struct usb_serial *serial; ++ int length = 0; ++ int i; ++ off_t begin = 0; ++ ++ mydbg("%s\n", __FUNCTION__); ++ length += sprintf (page, "usbserinfo:1.0 driver:%s\n", DRIVER_VERSION); ++ for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) { ++ serial = get_serial_by_minor(i); ++ if (serial == NULL) ++ continue; ++ ++ length += sprintf (page+length, "%d:\n", i); ++ length += sprintf (page+length, " vendor:%04x product:%04x\n", serial->vendor, serial->product); ++ length += sprintf (page+length, " num_ports:%d\n", serial->num_ports); ++ length += sprintf (page+length, " port:%d\n", i - serial->minor + 1); ++ ++// usb_make_path(serial->dev, tmp, sizeof(tmp)); ++// length += sprintf (page+length, " path:%s", tmp); ++ ++ length += sprintf (page+length, "\n"); ++ if ((length + begin) > (off + count)) ++ goto done; ++ if ((length + begin) < off) { ++ begin += length; ++ length = 0; ++ } ++ } ++ *eof = 1; ++done: ++ if (off >= (length + begin)) ++ return 0; ++ *start = page + (off-begin); ++ return ((count < begin+length-off) ? count : begin+length-off); ++} ++ ++ ++ ++int ioctl_serial_usb (struct inode *innod, struct file *filp, unsigned int cmd, ++ unsigned long arg) ++{ ++ ++ unsigned err; ++ unsigned ucOPR_NewValue, uc_Value; ++ int *p_Num_of_adapters, counts, index, *p_QMCR_Value; ++ struct identity *p_Identity_of; ++ struct identity Identity_of; ++ struct usb_serial *lastserial, *serial; ++ ++ mydbg(KERN_DEBUG"ioctl_serial_usb cmd =\n"); ++ if (_IOC_TYPE(cmd) != SERIALQT_PCI_IOC_MAGIC) ++ return -ENOTTY; ++ if (_IOC_NR(cmd) > SERIALQT_IOC_MAXNR) ++ return -ENOTTY; ++ mydbg(KERN_DEBUG"ioctl_serial_usb cmd = 0x%x\n", cmd); ++ err = 0; ++ switch (cmd) ++ { ++ ++ ++ case SERIALQT_WRITE_QMCR: ++ err = -ENOTTY; //initialize as error so if we don't find this one we give//an error. ++ index = arg >> 16; ++ counts = 0; ++ ++ ucOPR_NewValue = arg; ++ ++ ++ err = EmulateWriteQMCR_Reg(index, ucOPR_NewValue); ++ break; ++ ++ case SERIALQT_READ_QMCR: ++ err = -ENOTTY; //initialize as error so if we don't find this one we give ++ //an error. ++ p_QMCR_Value = (int *)arg; ++ index = arg >> 16; ++ counts = 0; ++ ++ ++ ++ err = EmulateReadQMCR_Reg(index, &uc_Value); ++ if (err == 0) ++ { ++ err = put_user(uc_Value, p_QMCR_Value); ++ } ++ break; ++ ++ case SERIALQT_GET_NUMOF_UNITS: ++ p_Num_of_adapters = (int *)arg; ++ counts = 0; //Initialize counts to zero ++ //struct usb_serial *lastserial = serial_table[0], *serial; ++ lastserial = serial_table[0]; ++ ++ mydbg(KERN_DEBUG"SERIALQT_GET_NUMOF_UNITS \n"); ++ //if first pointer is nonull, we at least have one box ++ if(lastserial) ++ counts = 1; //we at least have one box ++ ++ for (index = 1; index < SERIAL_TTY_MINORS ; index++) ++ { ++ serial = serial_table[index]; ++ if(serial) ++ { ++ if(serial != lastserial) ++ { ++ //we had a change in the array, hence another box is there ++ lastserial = serial; ++ counts++; ++ } ++ } ++ else ++ break; ++ } ++ ++ mydbg(KERN_DEBUG"ioctl_serial_usb writting counts = %d", counts); ++ ++ err = put_user(counts, p_Num_of_adapters); ++ ++ ++ break; ++ case SERIALQT_GET_THIS_UNIT: ++ counts = 0; ++ p_Identity_of = (struct identity *)arg; ++ //copy user structure to local variable ++ get_user(Identity_of.index, &p_Identity_of->index); ++ mydbg(KERN_DEBUG"SERIALQT_GET_THIS_UNIT Identity_of.index\n"); ++ mydbg(KERN_DEBUG"SERIALQT_GET_THIS_UNIT Identity_of.index= 0x%x\n", Identity_of.index); ++ ++ err = -ENOTTY; //initialize as error so if we don't find this one we give ++ //an error. ++ serial = find_the_box(Identity_of.index); ++ if(serial) ++ { ++ err = put_user(serial->product, &p_Identity_of->n_identity); ++ ++ } ++ break; ++ ++ case SERIALQT_IS422_EXTENDED: ++ err = -ENOTTY; //initialize as error so if we don't find this one we give ++ mydbg(KERN_DEBUG"SERIALQT_IS422_EXTENDED \n"); ++ //an error. ++ index = arg >> 16; ++ ++ ++ counts = 0; ++ ++ mydbg(KERN_DEBUG"SERIALQT_IS422_EXTENDED, looking Identity_of.indext = 0x%x\n",index); ++ serial = find_the_box(index); ++ if(serial) ++ { ++ mydbg("%s index = 0x%x, serial = 0x%p\n", __FUNCTION__, index, serial); ++ for (counts = 0; serqt_422_table[counts] != 0; counts++) ++ { ++ ++ mydbg("%s serial->product = = 0x%x, serqt_422_table[counts] = 0x%x\n", __FUNCTION__, serial->product, serqt_422_table[counts]); ++ if(serial->product == serqt_422_table[counts]) ++ { ++ err = 0; ++ ++ mydbg("%s found match for 422extended\n", __FUNCTION__); ++ break; ++ } ++ } ++ } ++ break; ++ ++ ++ ++ ++ default: ++ err = -ENOTTY; ++ ++ ++ ++ ++ } //End switch ++ ++ mydbg("%s returning err = 0x%x\n", __FUNCTION__, err); ++ return err; ++} ++ ++ ++ ++static struct usb_serial *find_the_box(unsigned int index) ++{ ++ struct usb_serial *lastserial, *foundserial, *serial; ++ int counts = 0, index2; ++ lastserial = serial_table[0]; ++ foundserial = NULL; ++ for (index2 = 0; index2 < SERIAL_TTY_MINORS ; index2++) ++ { ++ serial = serial_table[index2]; ++ ++ mydbg("%s index = 0x%x, index2 = 0x%x, serial = 0x%p\n", __FUNCTION__, index, index2, serial); ++ ++ if(serial) ++ { ++ //first see if this is the unit we'er looking for ++ mydbg("%s inside if(serial) counts = 0x%x , index = 0x%x\n", __FUNCTION__, counts, index); ++ if(counts == index) ++ { ++ //we found the one we're looking for, copythe product Id to user ++ ++ mydbg("%s we found the one we're looking for serial = 0x%p\n", __FUNCTION__, serial); ++ foundserial = serial; ++ break; ++ } ++ ++ if(serial != lastserial) ++ { ++ //when we have a change in the pointer ++ lastserial = serial; ++ counts++; ++ } ++ } ++ else ++ break; // no matches ++ } ++ ++ mydbg("%s returning foundserial = 0x%p\n", __FUNCTION__, foundserial); ++ return foundserial; ++} ++ ++ ++ ++ static int EmulateWriteQMCR_Reg(int index, unsigned uc_value) ++ { ++ ++ __u16 ATC_Mode = 0; ++ struct usb_serial *serial; ++ int status; ++ struct qt_get_device_data DeviceData; ++ unsigned uc_temp = 0; ++ mydbg("Inside %s, uc_value = 0x%x\n", __FUNCTION__, uc_value); ++ ++ DeviceData.porta = 0; ++ DeviceData.portb = 0; ++ serial = find_the_box(index); ++ //Determine Duplex mode ++ if(!(serial)) ++ return -ENOTTY; ++ status = box_get_device(serial, &DeviceData); ++ if (status < 0) ++ { ++ mydbg(__FILE__"box_set_device failed\n"); ++ return status; ++ } ++ ++ uc_temp = uc_value & QMCR_HALF_DUPLEX_MASK; ++ switch (uc_temp) ++ { ++ case QMCR_FULL_DUPLEX: ++ DeviceData.porta &= ~DUPMODE_BITS; ++ DeviceData.porta |= FULL_DUPLEX; ++ ATC_Mode = ATC_DISABLED; ++ break; ++ case QMCR_HALF_DUPLEX_RTS: ++ DeviceData.porta &= ~DUPMODE_BITS; ++ DeviceData.porta |= HALF_DUPLEX_RTS; ++ ATC_Mode = ATC_RTS_ENABLED; ++ break; ++ case QMCR_HALF_DUPLEX_DTR: ++ DeviceData.porta &= ~DUPMODE_BITS; ++ DeviceData.porta |= HALF_DUPLEX_DTR; ++ ATC_Mode = ATC_DTR_ENABLED; ++ break; ++ default: ++ break; ++ } ++ ++ uc_temp = uc_value & QMCR_CONNECTOR_MASK; ++ switch (uc_temp) ++ { ++ case QMCR_MODEM_CONTROL: ++ DeviceData.portb &= ~LOOPMODE_BITS; //reset connection bits ++ DeviceData.portb |= MODEM_CTRL; ++ break; ++ case QMCR_ALL_LOOPBACK: ++ DeviceData.portb &= ~LOOPMODE_BITS; //reset connection bits ++ DeviceData.portb |= ALL_LOOPBACK; ++ break; ++ } ++ ++ mydbg(__FILE__"Calling box_set_device with failed\n"); ++ status = box_set_device(serial, &DeviceData); ++ if (status < 0) ++ { ++ mydbg(__FILE__"box_set_device failed\n"); ++ return status; ++ } ++ ++ if(uc_value & QMCR_RX_EN_MASK) //This bit (otherwise unused) i'll used to detect whether ATC is selected ++ { ++ ++ mydbg(__FILE__"calling BoxsetATC with DeviceData.porta = 0x%x and DeviceData.portb = 0x%x\n", DeviceData.porta, DeviceData.portb); ++ status = BoxSetATC(serial, ATC_Mode); ++ if (status < 0) ++ { ++ mydbg(__FILE__"BoxSetATC failed\n"); ++ return status; ++ } ++ } ++ else ++ { ++ ++ mydbg(__FILE__"calling BoxsetATC with DeviceData.porta = 0x%x and DeviceData.portb = 0x%x\n", DeviceData.porta, DeviceData.portb); ++ status = BoxSetATC(serial, ATC_DISABLED); ++ if (status < 0) ++ { ++ mydbg(__FILE__"BoxSetATC failed\n"); ++ return status; ++ } ++ } ++ ++ ++ return 0; ++ ++ } ++ ++ ++static int EmulateReadQMCR_Reg(int index, unsigned *uc_value) ++{ ++ struct usb_serial *serial; ++ int status; ++ struct qt_get_device_data DeviceData; ++ __u8 uc_temp; ++ ++ *uc_value = 0; ++ ++ serial = find_the_box(index); ++ if(!(serial)) ++ return -ENOTTY; ++ ++ status = box_get_device(serial, &DeviceData); ++ if (status < 0) ++ { ++ mydbg(__FILE__"box_get_device failed\n"); ++ return status; ++ } ++ uc_temp = DeviceData.porta & DUPMODE_BITS; ++ switch (uc_temp) ++ { ++ case FULL_DUPLEX: ++ *uc_value |= QMCR_FULL_DUPLEX; ++ break; ++ case HALF_DUPLEX_RTS: ++ *uc_value |= QMCR_HALF_DUPLEX_RTS; ++ break; ++ case HALF_DUPLEX_DTR: ++ *uc_value |= QMCR_HALF_DUPLEX_DTR; ++ break; ++ default: ++ break; ++ } ++ ++ uc_temp = DeviceData.portb & LOOPMODE_BITS; //I use this for ATC control se ++ ++ switch (uc_temp) ++ { ++ case ALL_LOOPBACK: ++ *uc_value |= QMCR_ALL_LOOPBACK; ++ break; ++ case MODEM_CTRL: ++ *uc_value |= QMCR_MODEM_CONTROL; ++ break; ++ default: ++ break; ++ ++ } ++ return 0; ++ ++ ++ } ++ ++static int __init serqt_usb_init(void) ++{ ++ int i, result; ++ int status = 0; ++ ++ mydbg("%s\n", __FUNCTION__); ++ result = tty_register_driver(&serial_tty_driver); ++ if (result) { ++ mydbg("tty_register_driver failed error = 0x%x", result); ++ return result; ++ } ++ ++ /* Initalize our global data */ ++ for (i = 0; i < SERIAL_TTY_MINORS; ++i) ++ serial_table[i] = NULL; ++ ++ /* register this driver with the USB subsystem */ ++ result = usb_register(&serqt_usb_driver); ++ if (result < 0) { ++ err("usb_register failed for the "__FILE__" driver. Error number %d", result); ++ return result; ++ } ++ status = 0; // Dynamic assignment of major number ++ major_number = register_chrdev(status, "SerialQT_USB", &serialqt_usb_fops); ++ if (major_number < 0) { ++ mydbg(KERN_DEBUG"No devices found \n\n"); ++ return -EBUSY; ++ } else ++ mydbg(KERN_DEBUG"SerQT_USB major number assignment = %d \n\n", major_number); ++ ++ info(DRIVER_DESC " " DRIVER_VERSION); ++ return 0; ++} ++ ++static void __exit serqt_usb_exit(void) ++{ ++ /* deregister this driver with the USB subsystem */ ++ usb_deregister(&serqt_usb_driver); ++ tty_unregister_driver(&serial_tty_driver); ++ unregister_chrdev(major_number, "SerialQT_USB"); ++} ++ ++module_init(serqt_usb_init); ++module_exit(serqt_usb_exit); ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); |
