omninet.c revision 90ab5ee94171b3e28de6bb42ee30b527014e0be7
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB ZyXEL omni.net LCD PLUS driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 44d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * This program is free software; you can redistribute it and/or 54d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * modify it under the terms of the GNU General Public License version 64d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * 2 as published by the Free Software Foundation. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox * See Documentation/usb/usb-serial.txt for more information on using this 9f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox * driver 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Please report both successes and troubles to the author at omninet@kroah.com 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 22f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox#include <linux/uaccess.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 24a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2690ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool debug; 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version Information 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "v1.1" 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_AUTHOR "Alessandro Zummo" 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver" 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZYXEL_VENDOR_ID 0x0586 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZYXEL_OMNINET_ID 0x1000 37f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox/* This one seems to be a re-branded ZyXEL device */ 38f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox#define BT_IGNITIONPRO_ID 0x2000 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* function prototypes */ 41a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int omninet_open(struct tty_struct *tty, struct usb_serial_port *port); 42335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void omninet_close(struct usb_serial_port *port); 43f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic void omninet_read_bulk_callback(struct urb *urb); 44f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic void omninet_write_bulk_callback(struct urb *urb); 45f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, 46f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox const unsigned char *buf, int count); 47f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic int omninet_write_room(struct tty_struct *tty); 48f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void omninet_disconnect(struct usb_serial *serial); 49f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void omninet_release(struct usb_serial *serial); 50f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic int omninet_attach(struct usb_serial *serial); 51f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox 527d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table[] = { 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) }, 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan CoxMODULE_DEVICE_TABLE(usb, id_table); 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver omninet_driver = { 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "omninet", 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = usb_serial_probe, 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = usb_serial_disconnect, 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table, 65ba9dc657af86d05d2971633e57d1f6f94ed60472Greg Kroah-Hartman .no_dynamic_id = 1, 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver zyxel_omninet_device = { 7018fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .driver = { 7118fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .owner = THIS_MODULE, 72269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .name = "omninet", 7318fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman }, 74269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .description = "ZyXEL - omni.net lcd plus usb", 75d9b1b787736852f462dbf277b3ca708cbbf693aeJohannes Hölzl .usb_driver = &omninet_driver, 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table, 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_ports = 1, 785ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum .attach = omninet_attach, 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = omninet_open, 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = omninet_close, 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = omninet_write, 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = omninet_write_room, 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_bulk_callback = omninet_read_bulk_callback, 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_bulk_callback = omninet_write_bulk_callback, 85f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .disconnect = omninet_disconnect, 86f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .release = omninet_release, 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The protocol. 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The omni.net always exchange 64 bytes of data with the host. The first 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * four bytes are the control header, you can see it in the above structure. 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_seq is a sequence number. Don't know if/how it's used. 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_len is the length of the data bytes in the packet. 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_xxx Bit-mapped, related to handshaking and status info. 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I normally set it to 0x03 in trasmitted frames. 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7: Active when the TA is in a CONNECTed state. 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6: unknown 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5: handshaking, unknown 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4: handshaking, unknown 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3: unknown, usually 0 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2: unknown, usually 0 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1: handshaking, unknown, usually set to 1 in trasmitted frames 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0: handshaking, unknown, usually set to 1 in trasmitted frames 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_pad Probably a pad byte. 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * After the header you will find data bytes if oh_len was greater than zero. 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 113f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstruct omninet_header { 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_seq; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_len; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_xxx; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_pad; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 120f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstruct omninet_data { 121f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox __u8 od_outseq; /* Sequence number for bulk_out URBs */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 124f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic int omninet_attach(struct usb_serial *serial) 1255ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum{ 1265ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum struct omninet_data *od; 1275ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum struct usb_serial_port *port = serial->port[0]; 1285ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum 129f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox od = kmalloc(sizeof(struct omninet_data), GFP_KERNEL); 130f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox if (!od) { 131194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", 132194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__, sizeof(struct omninet_data)); 1335ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum return -ENOMEM; 1345ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum } 1355ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum usb_set_serial_port_data(port, od); 1365ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum return 0; 1375ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum} 1385ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum 139a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *wport; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = 0; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 145441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport = serial->port[1]; 1484a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_port_tty_set(&wport->port, tty); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start reading from the device */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(port->read_urb, GFP_KERNEL); 152f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox if (result) 153194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, 154194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "%s - failed submitting read urb, error %d\n", 155194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__, result); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 159335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void omninet_close(struct usb_serial_port *port) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 161441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kill_urb(port->read_urb); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OMNINET_DATAOFFSET 0x04 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OMNINET_HEADERLEN sizeof(struct omninet_header) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 170f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic void omninet_read_bulk_callback(struct urb *urb) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 172cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct omninet_header *header = (struct omninet_header *) &data[0]; 175fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman int status = urb->status; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 1774944d40054d73b2f8d7d546f55c206eb3baf2710Alan Cox int i; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 179441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman if (status) { 182fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman dbg("%s - nonzero read bulk status received: %d", 183441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison __func__, status); 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 187f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox if (debug && header->oh_xxx != 0x30) { 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->actual_length) { 189f45ba776da4fe6c9a9eddd42b0fd5d1f15c260f3Joe Perches printk(KERN_DEBUG "%s: omninet_read %d: ", 190f45ba776da4fe6c9a9eddd42b0fd5d1f15c260f3Joe Perches __FILE__, header->oh_len); 191f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox for (i = 0; i < (header->oh_len + 192f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox OMNINET_HEADERLEN); i++) 193f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox printk("%.2x ", data[i]); 194f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox printk("\n"); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->actual_length && header->oh_len) { 1994a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 2004a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET, 2014a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox header->oh_len); 2024a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_flip_buffer_push(tty); 2034a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_kref_put(tty); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Continue trying to always read */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(urb, GFP_ATOMIC); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 209194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, 210194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "%s - failed resubmitting read urb, error %d\n", 211194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__, result); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21495da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, 21595da310e66ee8090119596c70ca8432e57f9a97fAlan Cox const unsigned char *buf, int count) 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 217f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox struct usb_serial *serial = port->serial; 218f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox struct usb_serial_port *wport = serial->port[1]; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 220f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox struct omninet_data *od = usb_get_serial_port_data(port); 221f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox struct omninet_header *header = (struct omninet_header *) 222f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox wport->write_urb->transfer_buffer; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 226441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count == 0) { 229441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - write request of 0 bytes", __func__); 230f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox return 0; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 232507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman 233120f9dbc968c67f9448a4be535dfff6edc3ce711Johan Hovold if (!test_and_clear_bit(0, &port->write_urbs_free)) { 234441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - already writing", __func__); 235507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman return 0; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 240f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox memcpy(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, 241f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox buf, count); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 243f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox usb_serial_debug_data(debug, &port->dev, __func__, count, 244f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox wport->write_urb->transfer_buffer); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_seq = od->od_outseq++; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_len = count; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_xxx = 0x03; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_pad = 0x00; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send the data out the bulk port, always 64 bytes */ 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport->write_urb->transfer_buffer_length = 64; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); 255507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman if (result) { 256120f9dbc968c67f9448a4be535dfff6edc3ce711Johan Hovold set_bit(0, &wport->write_urbs_free); 257194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, 258194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "%s - failed submitting write urb, error %d\n", 259194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__, result); 260507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman } else 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = count; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 267f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic int omninet_write_room(struct tty_struct *tty) 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *wport = serial->port[1]; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 273a5b6f60c5a30c494017c7a2d11c4067f90d3d0dfAlan Cox int room = 0; /* Default: no room */ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 275120f9dbc968c67f9448a4be535dfff6edc3ce711Johan Hovold if (test_bit(0, &wport->write_urbs_free)) 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds room = wport->bulk_out_size - OMNINET_HEADERLEN; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 278441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - returns %d", __func__, room); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 280f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox return room; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 283f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic void omninet_write_bulk_callback(struct urb *urb) 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 285f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox/* struct omninet_header *header = (struct omninet_header *) 286f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox urb->transfer_buffer; */ 287cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 288fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman int status = urb->status; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 290759f3634267a67ac90f3fa7fc06510dfd43b4e45Joe Perches dbg("%s - port %0x", __func__, port->number); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 292120f9dbc968c67f9448a4be535dfff6edc3ce711Johan Hovold set_bit(0, &port->write_urbs_free); 293fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman if (status) { 294fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman dbg("%s - nonzero write bulk status received: %d", 295441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison __func__, status); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 299cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev usb_serial_port_softint(port); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 303f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void omninet_disconnect(struct usb_serial *serial) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3055ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum struct usb_serial_port *wport = serial->port[1]; 306f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 307f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox dbg("%s", __func__); 3085ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum 3095ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum usb_kill_urb(wport->write_urb); 310f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern} 311f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 312f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 313f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void omninet_release(struct usb_serial *serial) 314f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern{ 315f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern struct usb_serial_port *port = serial->port[0]; 316f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 317f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern dbg("%s", __func__); 318f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 3195ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum kfree(usb_get_serial_port_data(port)); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 323f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic int __init omninet_init(void) 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_serial_register(&zyxel_omninet_device); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_serial_register; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = usb_register(&omninet_driver); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed_usb_register; 332c197a8db59daf06dc5e77acd5a9681329cb22458Greg Kroah-Hartman printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" 333c197a8db59daf06dc5e77acd5a9681329cb22458Greg Kroah-Hartman DRIVER_DESC "\n"); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_register: 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_serial_deregister(&zyxel_omninet_device); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed_usb_serial_register: 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 342f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic void __exit omninet_exit(void) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 344f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox usb_deregister(&omninet_driver); 345f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox usb_serial_deregister(&zyxel_omninet_device); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(omninet_init); 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(omninet_exit); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 352f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan CoxMODULE_AUTHOR(DRIVER_AUTHOR); 353f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan CoxMODULE_DESCRIPTION(DRIVER_DESC); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not"); 358