0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/kernel.h>
0014 #include <linux/errno.h>
0015 #include <linux/slab.h>
0016 #include <linux/tty.h>
0017 #include <linux/tty_driver.h>
0018 #include <linux/tty_flip.h>
0019 #include <linux/module.h>
0020 #include <linux/uaccess.h>
0021 #include <linux/usb.h>
0022 #include <linux/usb/serial.h>
0023
0024 #define DRIVER_AUTHOR "Alessandro Zummo"
0025 #define DRIVER_DESC "USB ZyXEL omni.net Driver"
0026
0027 #define ZYXEL_VENDOR_ID 0x0586
0028 #define ZYXEL_OMNINET_ID 0x1000
0029 #define ZYXEL_OMNI_56K_PLUS_ID 0x1500
0030
0031 #define BT_IGNITIONPRO_ID 0x2000
0032
0033
0034 static void omninet_process_read_urb(struct urb *urb);
0035 static int omninet_prepare_write_buffer(struct usb_serial_port *port,
0036 void *buf, size_t count);
0037 static int omninet_calc_num_ports(struct usb_serial *serial,
0038 struct usb_serial_endpoints *epds);
0039 static int omninet_port_probe(struct usb_serial_port *port);
0040 static void omninet_port_remove(struct usb_serial_port *port);
0041
0042 static const struct usb_device_id id_table[] = {
0043 { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
0044 { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNI_56K_PLUS_ID) },
0045 { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) },
0046 { }
0047 };
0048 MODULE_DEVICE_TABLE(usb, id_table);
0049
0050 static struct usb_serial_driver zyxel_omninet_device = {
0051 .driver = {
0052 .owner = THIS_MODULE,
0053 .name = "omninet",
0054 },
0055 .description = "ZyXEL - omni.net usb",
0056 .id_table = id_table,
0057 .num_bulk_out = 2,
0058 .calc_num_ports = omninet_calc_num_ports,
0059 .port_probe = omninet_port_probe,
0060 .port_remove = omninet_port_remove,
0061 .process_read_urb = omninet_process_read_urb,
0062 .prepare_write_buffer = omninet_prepare_write_buffer,
0063 };
0064
0065 static struct usb_serial_driver * const serial_drivers[] = {
0066 &zyxel_omninet_device, NULL
0067 };
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092 struct omninet_header {
0093 __u8 oh_seq;
0094 __u8 oh_len;
0095 __u8 oh_xxx;
0096 __u8 oh_pad;
0097 };
0098
0099 struct omninet_data {
0100 __u8 od_outseq;
0101 };
0102
0103 static int omninet_calc_num_ports(struct usb_serial *serial,
0104 struct usb_serial_endpoints *epds)
0105 {
0106
0107 epds->bulk_out[0] = epds->bulk_out[1];
0108 epds->num_bulk_out = 1;
0109
0110 return 1;
0111 }
0112
0113 static int omninet_port_probe(struct usb_serial_port *port)
0114 {
0115 struct omninet_data *od;
0116
0117 od = kzalloc(sizeof(*od), GFP_KERNEL);
0118 if (!od)
0119 return -ENOMEM;
0120
0121 usb_set_serial_port_data(port, od);
0122
0123 return 0;
0124 }
0125
0126 static void omninet_port_remove(struct usb_serial_port *port)
0127 {
0128 struct omninet_data *od;
0129
0130 od = usb_get_serial_port_data(port);
0131 kfree(od);
0132 }
0133
0134 #define OMNINET_HEADERLEN 4
0135 #define OMNINET_BULKOUTSIZE 64
0136 #define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN)
0137
0138 static void omninet_process_read_urb(struct urb *urb)
0139 {
0140 struct usb_serial_port *port = urb->context;
0141 const struct omninet_header *hdr = urb->transfer_buffer;
0142 const unsigned char *data;
0143 size_t data_len;
0144
0145 if (urb->actual_length <= OMNINET_HEADERLEN || !hdr->oh_len)
0146 return;
0147
0148 data = (char *)urb->transfer_buffer + OMNINET_HEADERLEN;
0149 data_len = min_t(size_t, urb->actual_length - OMNINET_HEADERLEN,
0150 hdr->oh_len);
0151 tty_insert_flip_string(&port->port, data, data_len);
0152 tty_flip_buffer_push(&port->port);
0153 }
0154
0155 static int omninet_prepare_write_buffer(struct usb_serial_port *port,
0156 void *buf, size_t count)
0157 {
0158 struct omninet_data *od = usb_get_serial_port_data(port);
0159 struct omninet_header *header = buf;
0160
0161 count = min_t(size_t, count, OMNINET_PAYLOADSIZE);
0162
0163 count = kfifo_out_locked(&port->write_fifo, buf + OMNINET_HEADERLEN,
0164 count, &port->lock);
0165
0166 header->oh_seq = od->od_outseq++;
0167 header->oh_len = count;
0168 header->oh_xxx = 0x03;
0169 header->oh_pad = 0x00;
0170
0171
0172 return OMNINET_BULKOUTSIZE;
0173 }
0174
0175 module_usb_serial_driver(serial_drivers, id_table);
0176
0177 MODULE_AUTHOR(DRIVER_AUTHOR);
0178 MODULE_DESCRIPTION(DRIVER_DESC);
0179 MODULE_LICENSE("GPL v2");