omninet.c revision ba9dc657af86d05d2971633e57d1f6f94ed60472
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB ZyXEL omni.net LCD PLUS driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See Documentation/usb/usb-serial.txt for more information on using this driver 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Please report both successes and troubles to the author at omninet@kroah.com 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (05/30/2001) gkh 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * switched from using spinlock to a semaphore, which fixes lots of problems. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (04/08/2001) gb 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Identify version on module load. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (11/01/2000) Adam J. Richter 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usb_device_id table support 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (10/05/2000) gkh 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixed bug with urb->dev not being set properly, now that the usb 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * core needs it. 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (08/28/2000) gkh 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Added locks for SMP safeness. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than once. 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixed potential race in omninet_write_bulk_callback 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (07/19/2000) gkh 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Added module_init and module_exit functions to handle the fact that this 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver is a loadable module now. 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "usb-serial.h" 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "v1.1" 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Alessandro Zummo" 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver" 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZYXEL_VENDOR_ID 0x0586 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZYXEL_OMNINET_ID 0x1000 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BT_IGNITIONPRO_ID 0x2000 /* This one seems to be a re-branded ZyXEL device */ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* function prototypes */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int omninet_open (struct usb_serial_port *port, struct file *filp); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_close (struct usb_serial_port *port, struct file *filp); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_read_bulk_callback (struct urb *urb, struct pt_regs *regs); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int omninet_write_room (struct usb_serial_port *port); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_shutdown (struct usb_serial *serial); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id id_table [] = { 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) }, 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE (usb, id_table); 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver omninet_driver = { 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "omninet", 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = usb_serial_probe, 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = usb_serial_disconnect, 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table, 88ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman .no_dynamic_id = 1, 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver zyxel_omninet_device = { 9318fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .driver = { 9418fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .owner = THIS_MODULE, 95269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .name = "omninet", 9618fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman }, 97269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .description = "ZyXEL - omni.net lcd plus usb", 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table, 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_interrupt_in = 1, 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_bulk_in = 1, 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_bulk_out = 2, 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_ports = 1, 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = omninet_open, 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = omninet_close, 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = omninet_write, 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = omninet_write_room, 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_bulk_callback = omninet_read_bulk_callback, 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_bulk_callback = omninet_write_bulk_callback, 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .shutdown = omninet_shutdown, 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The protocol. 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The omni.net always exchange 64 bytes of data with the host. The first 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * four bytes are the control header, you can see it in the above structure. 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_seq is a sequence number. Don't know if/how it's used. 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_len is the length of the data bytes in the packet. 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_xxx Bit-mapped, related to handshaking and status info. 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I normally set it to 0x03 in trasmitted frames. 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7: Active when the TA is in a CONNECTed state. 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6: unknown 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5: handshaking, unknown 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4: handshaking, unknown 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3: unknown, usually 0 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 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 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 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. 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct omninet_header 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_seq; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_len; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_xxx; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_pad; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct omninet_data 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 od_outseq; // Sequence number for bulk_out URBs 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int omninet_open (struct usb_serial_port *port, struct file *filp) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *wport; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct omninet_data *od; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = 0; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if( !od ) { 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct omninet_data)); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_serial_port_data(port, od); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport = serial->port[1]; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport->tty = port->tty; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start reading from the device */ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb(port->read_urb, serial->dev, 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds omninet_read_bulk_callback, port); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(port->read_urb, GFP_KERNEL); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s - failed submitting read urb, error %d", __FUNCTION__, result); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_close (struct usb_serial_port *port, struct file * filp) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *wport; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - port %d", __FUNCTION__, port->number); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport = serial->port[1]; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kill_urb(wport->write_urb); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kill_urb(port->read_urb); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911bc3c9e1e44c2059fe2ffa6ff70ad0a925d7b05fJesper Juhl kfree(usb_get_serial_port_data(port)); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OMNINET_DATAOFFSET 0x04 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OMNINET_HEADERLEN sizeof(struct omninet_header) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_read_bulk_callback (struct urb *urb, struct pt_regs *regs) 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *port = (struct usb_serial_port *)urb->context; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct omninet_header *header = (struct omninet_header *) &data[0]; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// dbg("omninet_read_bulk_callback"); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->status) { 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 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]); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("\n"); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 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, 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 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); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 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 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 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; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// dbg("omninet_write port %d", port->number); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count == 0) { 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - write request of 0 bytes", __FUNCTION__); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 260507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman 261507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman spin_lock(&port->lock); 262507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman if (port->write_urb_busy) { 263507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman spin_unlock(&port->lock); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - already writing", __FUNCTION__); 265507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman return 0; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 267507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman port->write_urb_busy = 1; 268507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman spin_unlock(&port->lock); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 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 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_seq = od->od_outseq++; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_len = count; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_xxx = 0x03; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 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); 286507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman if (result) { 287507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman port->write_urb_busy = 0; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err("%s - failed submitting write urb, error %d", __FUNCTION__, result); 289507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman } 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 303507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman if (wport->write_urb_busy) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds room = wport->bulk_out_size - OMNINET_HEADERLEN; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// dbg("omninet_write_room returns %d", room); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (room); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs) 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 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// dbg("omninet_write_bulk_callback, port %0x\n", port); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 318507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman port->write_urb_busy = 0; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->status) { 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule_work(&port->work); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// dbg("omninet_write_bulk_callback, tty %0x\n", tty); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void omninet_shutdown (struct usb_serial *serial) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbg ("%s", __FUNCTION__); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init omninet_init (void) 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_serial_register(&zyxel_omninet_device); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_serial_register; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&omninet_driver); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_register; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info(DRIVER_VERSION ":" DRIVER_DESC); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register: 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister(&zyxel_omninet_device); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register: 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit omninet_exit (void) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_deregister (&omninet_driver); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister (&zyxel_omninet_device); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(omninet_init); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(omninet_exit); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR( DRIVER_AUTHOR ); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION( DRIVER_DESC ); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not"); 370