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, 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68ea65370d025f5005649e5cb37c4d025e92c6fc38Greg Kroah-Hartmanstatic struct usb_serial_driver zyxel_omninet_device = { 6918fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .driver = { 7018fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman .owner = THIS_MODULE, 71269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .name = "omninet", 7218fcac353fdc7cd072b0d24c8667042e675a4c11Greg Kroah-Hartman }, 73269bda1c123c7caf88e1deb2264f9086f0344192Greg Kroah-Hartman .description = "ZyXEL - omni.net lcd plus usb", 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = id_table, 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .num_ports = 1, 765ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum .attach = omninet_attach, 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = omninet_open, 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = omninet_close, 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = omninet_write, 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_room = omninet_write_room, 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read_bulk_callback = omninet_read_bulk_callback, 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write_bulk_callback = omninet_write_bulk_callback, 83f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .disconnect = omninet_disconnect, 84f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .release = omninet_release, 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 87f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = { 88f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern &zyxel_omninet_device, NULL 89f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern}; 90f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The protocol. 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The omni.net always exchange 64 bytes of data with the host. The first 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * four bytes are the control header, you can see it in the above structure. 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_seq is a sequence number. Don't know if/how it's used. 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_len is the length of the data bytes in the packet. 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_xxx Bit-mapped, related to handshaking and status info. 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I normally set it to 0x03 in trasmitted frames. 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7: Active when the TA is in a CONNECTed state. 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6: unknown 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5: handshaking, unknown 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4: handshaking, unknown 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3: unknown, usually 0 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2: unknown, usually 0 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1: handshaking, unknown, usually set to 1 in trasmitted frames 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0: handshaking, unknown, usually set to 1 in trasmitted frames 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * oh_pad Probably a pad byte. 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * After the header you will find data bytes if oh_len was greater than zero. 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 115f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstruct omninet_header { 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_seq; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_len; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_xxx; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 oh_pad; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 122f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstruct omninet_data { 123f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox __u8 od_outseq; /* Sequence number for bulk_out URBs */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 126f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic int omninet_attach(struct usb_serial *serial) 1275ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum{ 1285ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum struct omninet_data *od; 1295ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum struct usb_serial_port *port = serial->port[0]; 1305ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum 131f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox od = kmalloc(sizeof(struct omninet_data), GFP_KERNEL); 132f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox if (!od) { 133194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", 134194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__, sizeof(struct omninet_data)); 1355ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum return -ENOMEM; 1365ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum } 1375ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum usb_set_serial_port_data(port, od); 1385ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum return 0; 1395ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum} 1405ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum 141a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *wport; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = 0; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 147441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport = serial->port[1]; 1504a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_port_tty_set(&wport->port, tty); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start reading from the device */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(port->read_urb, GFP_KERNEL); 154f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox if (result) 155194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, 156194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "%s - failed submitting read urb, error %d\n", 157194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__, result); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void omninet_close(struct usb_serial_port *port) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 163441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kill_urb(port->read_urb); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OMNINET_DATAOFFSET 0x04 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OMNINET_HEADERLEN sizeof(struct omninet_header) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 172f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic void omninet_read_bulk_callback(struct urb *urb) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 174cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct omninet_header *header = (struct omninet_header *) &data[0]; 177fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman int status = urb->status; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 1794944d40054d73b2f8d7d546f55c206eb3baf2710Alan Cox int i; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 183fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman if (status) { 184fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman dbg("%s - nonzero read bulk status received: %d", 185441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison __func__, status); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 189f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox if (debug && header->oh_xxx != 0x30) { 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->actual_length) { 191f45ba776da4fe6c9a9eddd42b0fd5d1f15c260f3Joe Perches printk(KERN_DEBUG "%s: omninet_read %d: ", 192f45ba776da4fe6c9a9eddd42b0fd5d1f15c260f3Joe Perches __FILE__, header->oh_len); 193f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox for (i = 0; i < (header->oh_len + 194f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox OMNINET_HEADERLEN); i++) 195f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox printk("%.2x ", data[i]); 196f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox printk("\n"); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->actual_length && header->oh_len) { 2014a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 2024a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET, 2034a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox header->oh_len); 2044a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_flip_buffer_push(tty); 2054a90f09b20f4622dcbff1f0e1e6bae1704f8ad8cAlan Cox tty_kref_put(tty); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Continue trying to always read */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(urb, GFP_ATOMIC); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 211194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman dev_err(&port->dev, 212194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "%s - failed resubmitting read urb, error %d\n", 213194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__, result); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21695da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, 21795da310e66ee8090119596c70ca8432e57f9a97fAlan Cox const unsigned char *buf, int count) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 219f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox struct usb_serial *serial = port->serial; 220f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox struct usb_serial_port *wport = serial->port[1]; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 222f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox struct omninet_data *od = usb_get_serial_port_data(port); 223f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox struct omninet_header *header = (struct omninet_header *) 224f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox wport->write_urb->transfer_buffer; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 228441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - port %d", __func__, port->number); 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count == 0) { 231441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - write request of 0 bytes", __func__); 232f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox return 0; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 234507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman 235120f9dbc968c67f9448a4be535dfff6edc3ce711Johan Hovold if (!test_and_clear_bit(0, &port->write_urbs_free)) { 236441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - already writing", __func__); 237507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman return 0; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 242f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox memcpy(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, 243f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox buf, count); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 245f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox usb_serial_debug_data(debug, &port->dev, __func__, count, 246f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox wport->write_urb->transfer_buffer); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_seq = od->od_outseq++; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_len = count; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_xxx = 0x03; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds header->oh_pad = 0x00; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send the data out the bulk port, always 64 bytes */ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wport->write_urb->transfer_buffer_length = 64; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); 257507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman if (result) { 258120f9dbc968c67f9448a4be535dfff6edc3ce711Johan Hovold set_bit(0, &wport->write_urbs_free); 25922a416c4e0f2179b57028e084ac0ed2c110333bdJohan Hovold dev_err_console(port, 260194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman "%s - failed submitting write urb, error %d\n", 261194343d9364ea07c9f27c4505380a15a905e8a24Greg Kroah-Hartman __func__, result); 262507ca9bc0476662f3463888d583864834eab1e11Greg Kroah-Hartman } else 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = count; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 269f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic int omninet_write_room(struct tty_struct *tty) 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial_port *wport = serial->port[1]; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 275a5b6f60c5a30c494017c7a2d11c4067f90d3d0dfAlan Cox int room = 0; /* Default: no room */ 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 277120f9dbc968c67f9448a4be535dfff6edc3ce711Johan Hovold if (test_bit(0, &wport->write_urbs_free)) 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds room = wport->bulk_out_size - OMNINET_HEADERLEN; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 280441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison dbg("%s - returns %d", __func__, room); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 282f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox return room; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 285f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Coxstatic void omninet_write_bulk_callback(struct urb *urb) 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 287f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox/* struct omninet_header *header = (struct omninet_header *) 288f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox urb->transfer_buffer; */ 289cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 290fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman int status = urb->status; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 292759f3634267a67ac90f3fa7fc06510dfd43b4e45Joe Perches dbg("%s - port %0x", __func__, port->number); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 294120f9dbc968c67f9448a4be535dfff6edc3ce711Johan Hovold set_bit(0, &port->write_urbs_free); 295fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman if (status) { 296fdc2deb3892e802e916d1df7b1587aa0dbf3b271Greg Kroah-Hartman dbg("%s - nonzero write bulk status received: %d", 297441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison __func__, status); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301cf2c7481d2ff7f0c266de873b2fe93883e9782f9Pete Zaitcev usb_serial_port_softint(port); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 305f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void omninet_disconnect(struct usb_serial *serial) 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3075ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum struct usb_serial_port *wport = serial->port[1]; 308f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 309f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan Cox dbg("%s", __func__); 3105ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum 3115ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum usb_kill_urb(wport->write_urb); 312f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern} 313f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 314f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 315f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void omninet_release(struct usb_serial *serial) 316f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern{ 317f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern struct usb_serial_port *port = serial->port[0]; 318f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 319f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern dbg("%s", __func__); 320f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 3215ec1862e7b612d804ca10a0475dccf98c857efecOliver Neukum kfree(usb_get_serial_port_data(port)); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3246384eaefd337b465417e9b64ebf74717703c0788Greg Kroah-Hartmanmodule_usb_serial_driver(omninet_driver, serial_drivers); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 326f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan CoxMODULE_AUTHOR(DRIVER_AUTHOR); 327f89d0dff2507b6bd486b7db59a5f6a733fbfaa12Alan CoxMODULE_DESCRIPTION(DRIVER_DESC); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, bool, S_IRUGO | S_IWUSR); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug enabled or not"); 332