omninet.c revision fdc2deb3892e802e916d1df7b1587aa0dbf3b271
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB ZyXEL omni.net LCD PLUS driver 30d6aa60b4ac9689b750e35cd66f5d7c053aff0f4Dave Airlie * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License version 6bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * 2 as published by the Free Software Foundation. 7bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * 8bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * See Documentation/usb/usb-serial.txt for more information on using this driver 9bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * 10bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * Please report both successes and troubles to the author at omninet@kroah.com 11bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * 12bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * (05/30/2001) gkh 13bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * switched from using spinlock to a semaphore, which fixes lots of problems. 14bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * 15bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * (04/08/2001) gb 16bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * Identify version on module load. 17bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * 18bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * (11/01/2000) Adam J. Richter 19bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * usb_device_id table support 20bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * 21bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * (10/05/2000) gkh 22bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * Fixed bug with urb->dev not being set properly, now that the usb 23bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * core needs it. 24bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * 25bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * (08/28/2000) gkh 26bc54fd1ad3c5972be339a08528ab631326ed2b38Dave Airlie * Added locks for SMP safeness. 270d6aa60b4ac9689b750e35cd66f5d7c053aff0f4Dave Airlie * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than once. 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixed potential race in omninet_write_bulk_callback 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3179e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * (07/19/2000) gkh 3279e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * Added module_init and module_exit functions to handle the fact that this 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver is a loadable module now. 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 4184b1fd103dbbe01b5905db1444d3fc8afa9a7207Dave Airlie#include <linux/tty.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 45d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5Keith Packard#include <linux/spinlock.h> 46d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5Keith Packard#include <asm/uaccess.h> 47d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5Keith Packard#include <linux/usb.h> 48585fb111348f7cdc30c6a1b903987612ddeafb23Jesse Barnes#include <linux/usb/serial.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug; 51d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5Keith Packard 52585fb111348f7cdc30c6a1b903987612ddeafb23Jesse Barnes/* 53d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5Keith Packard * Version Information 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "v1.1" 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Alessandro Zummo" 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver" 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZYXEL_VENDOR_ID 0x0586 6098787c057fdefdce6230ff46f2c1105835005a4cChris Wilson#define ZYXEL_OMNINET_ID 0x1000 6198787c057fdefdce6230ff46f2c1105835005a4cChris Wilson#define BT_IGNITIONPRO_ID 0x2000 /* This one seems to be a re-branded ZyXEL device */ 6298787c057fdefdce6230ff46f2c1105835005a4cChris Wilson 6398787c057fdefdce6230ff46f2c1105835005a4cChris Wilson/* function prototypes */ 6498787c057fdefdce6230ff46f2c1105835005a4cChris Wilsonstatic int omninet_open (struct usb_serial_port *port, struct file *filp); 6598787c057fdefdce6230ff46f2c1105835005a4cChris Wilsonstatic void omninet_close (struct usb_serial_port *port, struct file *filp); 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_read_bulk_callback (struct urb *urb); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_write_bulk_callback (struct urb *urb); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count); 69d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5Keith Packardstatic int omninet_write_room (struct usb_serial_port *port); 70d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5Keith Packardstatic void omninet_shutdown (struct usb_serial *serial); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int omninet_attach (struct usb_serial *serial); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5Keith Packardstatic struct usb_device_id id_table [] = { 74d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5Keith Packard { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, 75d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5Keith Packard { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) }, 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7820caafa6ecb2487d9b223aa33e7cc704f912a758Eric Anholt 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE (usb, id_table); 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packardstatic struct usb_driver omninet_driver = { 82398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .name = "omninet", 83398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .probe = usb_serial_probe, 84398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .disconnect = usb_serial_disconnect, 853043c60c485ad694392d3f71bd7ef9f5c5f7cfddEric Anholt .id_table = id_table, 86398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .no_dynamic_id = 1, 87398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard}; 88398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard 89398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard 90398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packardstatic struct usb_serial_driver zyxel_omninet_device = { 91398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .driver = { 92398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .owner = THIS_MODULE, 93398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .name = "omninet", 94398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard }, 95398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .description = "ZyXEL - omni.net lcd plus usb", 96398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .usb_driver = &omninet_driver, 97398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .id_table = id_table, 98398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .num_interrupt_in = 1, 99398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .num_bulk_in = 1, 100398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .num_bulk_out = 2, 101398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .num_ports = 1, 102398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .attach = omninet_attach, 103398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .open = omninet_open, 104398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .close = omninet_close, 105398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .write = omninet_write, 106398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .write_room = omninet_write_room, 107398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .read_bulk_callback = omninet_read_bulk_callback, 108398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .write_bulk_callback = omninet_write_bulk_callback, 109398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard .shutdown = omninet_shutdown, 1103043c60c485ad694392d3f71bd7ef9f5c5f7cfddEric Anholt}; 111398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard 112398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard 113398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard/* The protocol. 114398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * 115398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * The omni.net always exchange 64 bytes of data with the host. The first 116398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * four bytes are the control header, you can see it in the above structure. 117398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * 118398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * oh_seq is a sequence number. Don't know if/how it's used. 119398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * oh_len is the length of the data bytes in the packet. 120398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * oh_xxx Bit-mapped, related to handshaking and status info. 121398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * I normally set it to 0x03 in trasmitted frames. 122398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * 7: Active when the TA is in a CONNECTed state. 123398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * 6: unknown 124398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * 5: handshaking, unknown 125398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * 4: handshaking, unknown 126398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard * 3: unknown, usually 0 12784b1fd103dbbe01b5905db1444d3fc8afa9a7207Dave Airlie * 2: unknown, usually 0 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1: handshaking, unknown, usually set to 1 in trasmitted frames 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0: handshaking, unknown, usually set to 1 in trasmitted frames 1307c1c2871a6a3a114853ec6836e9035ac1c0c7f7aDave Airlie * oh_pad Probably a pad byte. 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * After the header you will find data bytes if oh_len was greater than zero. 13379e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes * 13479e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes */ 13579e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes 13679e539453b34e35f39299a899d263b0a1f1670bdJesse Barnesstruct omninet_header 13779e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes{ 13879e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes __u8 oh_seq; 13979e539453b34e35f39299a899d263b0a1f1670bdJesse Barnes __u8 oh_len; 140585fb111348f7cdc30c6a1b903987612ddeafb23Jesse Barnes __u8 oh_xxx; 141585fb111348f7cdc30c6a1b903987612ddeafb23Jesse Barnes __u8 oh_pad; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct omninet_data 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1467c1c2871a6a3a114853ec6836e9035ac1c0c7f7aDave Airlie __u8 od_outseq; // Sequence number for bulk_out URBs 1477c1c2871a6a3a114853ec6836e9035ac1c0c7f7aDave Airlie}; 1487c1c2871a6a3a114853ec6836e9035ac1c0c7f7aDave Airlie 1497c1c2871a6a3a114853ec6836e9035ac1c0c7f7aDave Airliestatic int omninet_attach (struct usb_serial *serial) 1507c1c2871a6a3a114853ec6836e9035ac1c0c7f7aDave Airlie{ 1517c1c2871a6a3a114853ec6836e9035ac1c0c7f7aDave Airlie struct omninet_data *od; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = serial->port[0]; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15484b1fd103dbbe01b5905db1444d3fc8afa9a7207Dave Airlie od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if( !od ) { 156ba8bbcf6ff4650712f64c0ef61139c73898e2165Jesse Barnes err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data)); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_serial_port_data(port, od); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 161ed4cb4142b242d8090d3811d5eb4abf6aa985bc8Eric Anholt} 162b5e89ed53ed8d24f83ba1941c07382af00ed238eDave Airlie 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int omninet_open (struct usb_serial_port *port, struct file *filp) 164ba8bbcf6ff4650712f64c0ef61139c73898e2165Jesse Barnes{ 165ba8bbcf6ff4650712f64c0ef61139c73898e2165Jesse Barnes struct usb_serial *serial = port->serial; 1663043c60c485ad694392d3f71bd7ef9f5c5f7cfddEric Anholt struct usb_serial_port *wport; 1673043c60c485ad694392d3f71bd7ef9f5c5f7cfddEric Anholt int result = 0; 168ba8bbcf6ff4650712f64c0ef61139c73898e2165Jesse Barnes 169ba8bbcf6ff4650712f64c0ef61139c73898e2165Jesse Barnes dbg("%s - port %d", __FUNCTION__, port->number); 170dc7a93190c21edbf3ed23e678ad04f852b9cff28Wang Zhenyu 171398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard wport = serial->port[1]; 172398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard wport->tty = port->tty; 173398c9cb20b5c6c5d1313912b937d653a46fec578Keith Packard 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start reading from the device */ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb(port->read_urb, serial->dev, 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, 178ba8bbcf6ff4650712f64c0ef61139c73898e2165Jesse Barnes omninet_read_bulk_callback, port); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(port->read_urb, GFP_KERNEL); 180ba8bbcf6ff4650712f64c0ef61139c73898e2165Jesse Barnes if (result) { 1817c1c2871a6a3a114853ec6836e9035ac1c0c7f7aDave Airlie err("%s - failed submitting read urb, error %d", __FUNCTION__, result); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1833a03ac1a0223f779a3de313523408ddb099e5679Dave Airlie 1843a03ac1a0223f779a3de313523408ddb099e5679Dave Airlie return result; 1853a03ac1a0223f779a3de313523408ddb099e5679Dave Airlie} 1863a03ac1a0223f779a3de313523408ddb099e5679Dave Airlie 1873a03ac1a0223f779a3de313523408ddb099e5679Dave Airliestatic void omninet_close (struct usb_serial_port *port, struct file * filp) 1883a03ac1a0223f779a3de313523408ddb099e5679Dave Airlie{ 1893a03ac1a0223f779a3de313523408ddb099e5679Dave Airlie dbg("%s - port %d", __FUNCTION__, port->number); 1903a03ac1a0223f779a3de313523408ddb099e5679Dave Airlie usb_kill_urb(port->read_urb); 191673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt} 192673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt 193673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt 194673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt#define OMNINET_DATAOFFSET 0x04 195673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt#define OMNINET_HEADERLEN sizeof(struct omninet_header) 196673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN) 197673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_read_bulk_callback (struct urb *urb) 199673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt{ 200673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt struct usb_serial_port *port = (struct usb_serial_port *)urb->context; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 202673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt struct omninet_header *header = (struct omninet_header *) &data[0]; 203673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt int status = urb->status; 204673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt int i; 205673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt int result; 206673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 2086fb88588555a18792a27f483887fe1f2af5f9c9bJesse Barnes 209673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt if (status) { 210673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt dbg("%s - nonzero read bulk status received: %d", 211673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt __FUNCTION__, status); 212673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt return; 213673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt } 214673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt 215673a394b1e3b69be886ff24abfd6df97c52e8d08Eric Anholt if ((debug) && (header->oh_xxx != 0x30)) { 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->actual_length) { 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) { 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("%.2x ", data[i]); 220a6b54f3f5050c0cbc0c35dd48064846c6302706bMichel Dänzer } 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("\n"); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2247c1c2871a6a3a114853ec6836e9035ac1c0c7f7aDave Airlie 2257c1c2871a6a3a114853ec6836e9035ac1c0c7f7aDave Airlie if (urb->actual_length && header->oh_len) { 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < header->oh_len; i++) { 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_insert_flip_char(port->tty, data[OMNINET_DATAOFFSET + i], 0); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tty_flip_buffer_push(port->tty); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Continue trying to always read */ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb(urb, port->serial->dev, 23484b1fd103dbbe01b5905db1444d3fc8afa9a7207Dave Airlie usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->transfer_buffer, urb->transfer_buffer_length, 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds omninet_read_bulk_callback, port); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(urb, GFP_ATOMIC); 238bf9d89295233ae2ba7b312c78ee5657307b09f4cHarvey Harrison if (result) 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24320caafa6ecb2487d9b223aa33e7cc704f912a758Eric Anholt 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count) 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *wport = serial->port[1]; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24920caafa6ecb2487d9b223aa33e7cc704f912a758Eric Anholt struct omninet_data *od = usb_get_serial_port_data(port); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct omninet_header *header = (struct omninet_header *) wport->write_urb->transfer_buffer; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 253dc7a93190c21edbf3ed23e678ad04f852b9cff28Wang Zhenyu 254585fb111348f7cdc30c6a1b903987612ddeafb23Jesse Barnes dbg("%s - port %d", __FUNCTION__, port->number); 255dc7a93190c21edbf3ed23e678ad04f852b9cff28Wang Zhenyu 256585fb111348f7cdc30c6a1b903987612ddeafb23Jesse Barnes if (count == 0) { 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - write request of 0 bytes", __FUNCTION__); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&wport->lock); 262c153f45f9b7e30289157bba3ff5682291df16caaEric Anholt if (wport->write_urb_busy) { 263c153f45f9b7e30289157bba3ff5682291df16caaEric Anholt spin_unlock_bh(&wport->lock); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - already writing", __FUNCTION__); 265c153f45f9b7e30289157bba3ff5682291df16caaEric Anholt return 0; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport->write_urb_busy = 1; 268c153f45f9b7e30289157bba3ff5682291df16caaEric Anholt spin_unlock_bh(&wport->lock); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 270ba8bbcf6ff4650712f64c0ef61139c73898e2165Jesse Barnes count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count); 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, wport->write_urb->transfer_buffer); 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2760d6aa60b4ac9689b750e35cd66f5d7c053aff0f4Dave Airlie header->oh_seq = od->od_outseq++; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_len = count; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_xxx = 0x03; 27920caafa6ecb2487d9b223aa33e7cc704f912a758Eric Anholt header->oh_pad = 0x00; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send the data out the bulk port, always 64 bytes */ 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport->write_urb->transfer_buffer_length = 64; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport->write_urb->dev = serial->dev; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport->write_urb_busy = 0; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s - failed submitting write urb, error %d", __FUNCTION__, result); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = count; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int omninet_write_room (struct usb_serial_port *port) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *wport = serial->port[1]; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int room = 0; // Default: no room 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wport->write_urb_busy) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds room = wport->bulk_out_size - OMNINET_HEADERLEN; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - returns %d", __FUNCTION__, room); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (room); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_write_bulk_callback (struct urb *urb) 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = (struct usb_serial_port *) urb->context; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status = urb->status; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %0x\n", __FUNCTION__, port->number); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->write_urb_busy = 0; 320b5e89ed53ed8d24f83ba1941c07382af00ed238eDave Airlie if (status) { 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - nonzero write bulk status received: %d", 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__, status); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_port_softint(port); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_shutdown (struct usb_serial *serial) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *wport = serial->port[1]; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = serial->port[0]; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("%s", __FUNCTION__); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kill_urb(wport->write_urb); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(usb_get_serial_port_data(port)); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init omninet_init (void) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_serial_register(&zyxel_omninet_device); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_serial_register; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&omninet_driver); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_register; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info(DRIVER_VERSION ":" DRIVER_DESC); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register: 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister(&zyxel_omninet_device); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register: 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 357bc5f4523f772cc7629c5c5a46cf4f2a07a5500b8Dave Airlie 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit omninet_exit (void) 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_deregister (&omninet_driver); 362201361a54ed187d8595a283e3a4ddb213bc8323bEric Anholt usb_serial_deregister (&zyxel_omninet_device); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(omninet_init); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(omninet_exit); 368de227f5f32775d86e5c780a7cffdd2e08574f7fbDave Airlie 36920caafa6ecb2487d9b223aa33e7cc704f912a758Eric AnholtMODULE_AUTHOR( DRIVER_AUTHOR ); 370de227f5f32775d86e5c780a7cffdd2e08574f7fbDave AirlieMODULE_DESCRIPTION( DRIVER_DESC ); 371c29b669caae4ed1630ef479e54bdde126a0378ecAlan HourihaneMODULE_LICENSE("GPL"); 372de227f5f32775d86e5c780a7cffdd2e08574f7fbDave Airlie 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not"); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds