157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman/* 257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman * Opticon USB barcode to serial driver 357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman * 4309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen * Copyright (C) 2011 Martin Jansen <martin.jansen@opticon.com> 5648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman * Copyright (C) 2008 - 2009 Greg Kroah-Hartman <gregkh@suse.de> 6648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman * Copyright (C) 2008 - 2009 Novell Inc. 757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman * 857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman * This program is free software; you can redistribute it and/or 957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman * modify it under the terms of the GNU General Public License version 1057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman * 2 as published by the Free Software Foundation. 1157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman */ 1257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 1357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman#include <linux/kernel.h> 1457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman#include <linux/init.h> 1557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman#include <linux/tty.h> 1657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman#include <linux/tty_driver.h> 175a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 1857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman#include <linux/tty_flip.h> 19faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman#include <linux/serial.h> 2057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman#include <linux/module.h> 2157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman#include <linux/usb.h> 2257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman#include <linux/usb/serial.h> 2357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman#include <linux/uaccess.h> 2457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 25309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen#define CONTROL_RTS 0x02 26309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen#define RESEND_CTS_STATE 0x03 27309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 28309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen/* max number of write urbs in flight */ 29309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen#define URB_UPPER_LIMIT 8 30309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 31309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen/* This driver works for the Opticon 1D barcode reader 32309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen * an examples of 1D barcode types are EAN, UPC, Code39, IATA etc.. */ 33309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen#define DRIVER_DESC "Opticon USB barcode to serial driver (1D)" 34309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 3590ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool debug; 3657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 377d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table[] = { 3857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman { USB_DEVICE(0x065a, 0x0009) }, 3957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman { }, 4057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman}; 4157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-HartmanMODULE_DEVICE_TABLE(usb, id_table); 4257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 4357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman/* This structure holds all of the individual device information */ 4457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartmanstruct opticon_private { 4557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct usb_device *udev; 4657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct usb_serial *serial; 4757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct usb_serial_port *port; 4857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman unsigned char *bulk_in_buffer; 4957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct urb *bulk_read_urb; 5057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman int buffer_size; 5157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman u8 bulk_address; 5257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman spinlock_t lock; /* protects the following flags */ 5357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman bool throttled; 5457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman bool actually_throttled; 5557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman bool rts; 56309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen bool cts; 57648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman int outstanding_urbs; 5857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman}; 5957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 60648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 61309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 62309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansenstatic void opticon_read_bulk_callback(struct urb *urb) 6357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman{ 6457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct opticon_private *priv = urb->context; 6557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman unsigned char *data = urb->transfer_buffer; 6657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct usb_serial_port *port = priv->port; 6757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman int status = urb->status; 6857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct tty_struct *tty; 6957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman int result; 7057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman int data_length; 71309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen unsigned long flags; 7257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 7357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 7457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 7557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman switch (status) { 7657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman case 0: 7757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman /* success */ 7857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman break; 7957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman case -ECONNRESET: 8057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman case -ENOENT: 8157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman case -ESHUTDOWN: 8257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman /* this urb is terminated, clean up */ 8357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dbg("%s - urb shutting down with status: %d", 8457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman __func__, status); 8557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman return; 8657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman default: 8757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dbg("%s - nonzero urb status received: %d", 8857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman __func__, status); 8957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman goto exit; 9057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } 9157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 9257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, 9357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman data); 9457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 9557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (urb->actual_length > 2) { 9657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman data_length = urb->actual_length - 2; 9757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 9857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman /* 9957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman * Data from the device comes with a 2 byte header: 10057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman * 10157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman * <0x00><0x00>data... 102309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen * This is real data to be sent to the tty layer 10357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman * <0x00><0x01)level 104309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen * This is a CTS level change, the third byte is the CTS 105309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen * value (0 for low, 1 for high). 10657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman */ 10757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if ((data[0] == 0x00) && (data[1] == 0x00)) { 10857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman /* real data, send it to the tty layer */ 10957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman tty = tty_port_tty_get(&port->port); 11057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (tty) { 11197cd8dc4ca9a1a5efb2cc38758e01492e3b013e2Alon Ziv tty_insert_flip_string(tty, data + 2, 11297cd8dc4ca9a1a5efb2cc38758e01492e3b013e2Alon Ziv data_length); 113a108bfcb372d8c4452701039308fb95747911c59Alan Cox tty_flip_buffer_push(tty); 11457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman tty_kref_put(tty); 11557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } 11657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } else { 11757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if ((data[0] == 0x00) && (data[1] == 0x01)) { 118309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen spin_lock_irqsave(&priv->lock, flags); 11925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* CTS status information package */ 12057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (data[2] == 0x00) 121309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen priv->cts = false; 12257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman else 123309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen priv->cts = true; 124309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen spin_unlock_irqrestore(&priv->lock, flags); 12557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } else { 126c6f694af8318a526c639306d9d07ee33cb7c168aAlon Ziv dev_dbg(&priv->udev->dev, 127c6f694af8318a526c639306d9d07ee33cb7c168aAlon Ziv "Unknown data packet received from the device:" 128c6f694af8318a526c639306d9d07ee33cb7c168aAlon Ziv " %2x %2x\n", 129c6f694af8318a526c639306d9d07ee33cb7c168aAlon Ziv data[0], data[1]); 13057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } 13157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } 13257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } else { 13357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dev_dbg(&priv->udev->dev, 1349ddc5b6f18fbac07d2746566b73b89e89fdd4e6aUwe Kleine-König "Improper amount of data received from the device, " 13557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman "%d bytes", urb->actual_length); 13657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } 13757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 13857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartmanexit: 13957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman spin_lock(&priv->lock); 14057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 14157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman /* Continue trying to always read if we should */ 14257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (!priv->throttled) { 14357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev, 14457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman usb_rcvbulkpipe(priv->udev, 14557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->bulk_address), 14657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->bulk_in_buffer, priv->buffer_size, 147309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen opticon_read_bulk_callback, priv); 14897cd8dc4ca9a1a5efb2cc38758e01492e3b013e2Alon Ziv result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC); 14957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (result) 15057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dev_err(&port->dev, 15157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman "%s - failed resubmitting read urb, error %d\n", 15257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman __func__, result); 15357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } else 15457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->actually_throttled = true; 15557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman spin_unlock(&priv->lock); 15657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman} 15757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 158309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansenstatic int send_control_msg(struct usb_serial_port *port, u8 requesttype, 159309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen u8 val) 160309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen{ 161309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen struct usb_serial *serial = port->serial; 162309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen int retval; 163309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen u8 buffer[2]; 164309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 165309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen buffer[0] = val; 166309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen /* Send the message to the vendor control endpoint 167309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen * of the connected device */ 168309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 169309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen requesttype, 170309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, 171309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 0, 0, buffer, 1, 0); 172309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 173309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen return retval; 174309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen} 175309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 176a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) 17757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman{ 17857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct opticon_private *priv = usb_get_serial_data(port->serial); 17957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman unsigned long flags; 18057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman int result = 0; 18157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 18257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 18357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 18457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman spin_lock_irqsave(&priv->lock, flags); 18557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->throttled = false; 18657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->actually_throttled = false; 18757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->port = port; 188309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen priv->rts = false; 18957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman spin_unlock_irqrestore(&priv->lock, flags); 19057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 191309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen /* Clear RTS line */ 192309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen send_control_msg(port, CONTROL_RTS, 0); 193309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 194309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen /* Setup the read URB and start reading from the device */ 19557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev, 19657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman usb_rcvbulkpipe(priv->udev, 19757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->bulk_address), 19857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->bulk_in_buffer, priv->buffer_size, 199309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen opticon_read_bulk_callback, priv); 200309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 201309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen /* clear the halt status of the enpoint */ 202309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen usb_clear_halt(priv->udev, priv->bulk_read_urb->pipe); 203309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 20457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman result = usb_submit_urb(priv->bulk_read_urb, GFP_KERNEL); 20557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (result) 20657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dev_err(&port->dev, 20757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman "%s - failed resubmitting read urb, error %d\n", 20857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman __func__, result); 209309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen /* Request CTS line state, sometimes during opening the current 210309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen * CTS state can be missed. */ 211309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen send_control_msg(port, RESEND_CTS_STATE, 1); 21257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman return result; 21357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman} 21457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 215335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void opticon_close(struct usb_serial_port *port) 21657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman{ 21757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct opticon_private *priv = usb_get_serial_data(port->serial); 21857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 21957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 22057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 22157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman /* shutdown our urbs */ 22257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman usb_kill_urb(priv->bulk_read_urb); 22357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman} 22457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 225309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansenstatic void opticon_write_control_callback(struct urb *urb) 226648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman{ 227648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman struct opticon_private *priv = urb->context; 228648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman int status = urb->status; 229648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman unsigned long flags; 230648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 231648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman /* free up the transfer buffer, as usb_free_urb() does not do this */ 232648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman kfree(urb->transfer_buffer); 233648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 2340d930e51cfe6f748339d7d13b3fad2b91a1d92c2Alon Ziv /* setup packet may be set if we're using it for writing */ 2350d930e51cfe6f748339d7d13b3fad2b91a1d92c2Alon Ziv kfree(urb->setup_packet); 2360d930e51cfe6f748339d7d13b3fad2b91a1d92c2Alon Ziv 237648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman if (status) 238648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman dbg("%s - nonzero write bulk status received: %d", 239648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman __func__, status); 240648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 241648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman spin_lock_irqsave(&priv->lock, flags); 242648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman --priv->outstanding_urbs; 243648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman spin_unlock_irqrestore(&priv->lock, flags); 244648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 245648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman usb_serial_port_softint(priv->port); 246648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman} 247648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 248648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartmanstatic int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, 249648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman const unsigned char *buf, int count) 250648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman{ 251648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman struct opticon_private *priv = usb_get_serial_data(port->serial); 252648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman struct usb_serial *serial = port->serial; 253648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman struct urb *urb; 254648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman unsigned char *buffer; 255648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman unsigned long flags; 256648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman int status; 257309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen struct usb_ctrlrequest *dr; 258648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 259648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 260648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 261648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman spin_lock_irqsave(&priv->lock, flags); 262648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman if (priv->outstanding_urbs > URB_UPPER_LIMIT) { 263648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman spin_unlock_irqrestore(&priv->lock, flags); 264759f3634267a67ac90f3fa7fc06510dfd43b4e45Joe Perches dbg("%s - write limit hit", __func__); 265648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman return 0; 266648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman } 267648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman priv->outstanding_urbs++; 268648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman spin_unlock_irqrestore(&priv->lock, flags); 269648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 270648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman buffer = kmalloc(count, GFP_ATOMIC); 271648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman if (!buffer) { 272648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman dev_err(&port->dev, "out of memory\n"); 273648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman count = -ENOMEM; 274309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 275648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman goto error_no_buffer; 276648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman } 277648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 278648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman urb = usb_alloc_urb(0, GFP_ATOMIC); 279648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman if (!urb) { 280648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman dev_err(&port->dev, "no more free urbs\n"); 281648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman count = -ENOMEM; 282648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman goto error_no_urb; 283648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman } 284648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 285648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman memcpy(buffer, buf, count); 286648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 287648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); 288648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 289309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen /* The conncected devices do not have a bulk write endpoint, 290309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen * to transmit data to de barcode device the control endpoint is used */ 291309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); 292b0795bbf6dc6bd0a7a37d9d1ef4558e9e2b0acd6Julia Lawall if (!dr) { 293b0795bbf6dc6bd0a7a37d9d1ef4558e9e2b0acd6Julia Lawall dev_err(&port->dev, "out of memory\n"); 294b0795bbf6dc6bd0a7a37d9d1ef4558e9e2b0acd6Julia Lawall count = -ENOMEM; 295b0795bbf6dc6bd0a7a37d9d1ef4558e9e2b0acd6Julia Lawall goto error; 296b0795bbf6dc6bd0a7a37d9d1ef4558e9e2b0acd6Julia Lawall } 297309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 298309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen dr->bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT; 299309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen dr->bRequest = 0x01; 300309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen dr->wValue = 0; 301309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen dr->wIndex = 0; 302309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen dr->wLength = cpu_to_le16(count); 303309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 304309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen usb_fill_control_urb(urb, serial->dev, 305309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen usb_sndctrlpipe(serial->dev, 0), 306309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen (unsigned char *)dr, buffer, count, 307309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen opticon_write_control_callback, priv); 308648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 309648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman /* send it down the pipe */ 310648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman status = usb_submit_urb(urb, GFP_ATOMIC); 311648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman if (status) { 312648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman dev_err(&port->dev, 313309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen "%s - usb_submit_urb(write endpoint) failed status = %d\n", 314648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman __func__, status); 315648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman count = status; 316648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman goto error; 317648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman } 318648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 319648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman /* we are done with this urb, so let the host driver 320648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman * really free it when it is finished with it */ 321648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman usb_free_urb(urb); 322648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 323648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman return count; 324648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartmanerror: 325648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman usb_free_urb(urb); 326648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartmanerror_no_urb: 327648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman kfree(buffer); 328648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartmanerror_no_buffer: 329648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman spin_lock_irqsave(&priv->lock, flags); 330648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman --priv->outstanding_urbs; 331648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman spin_unlock_irqrestore(&priv->lock, flags); 332648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman return count; 333648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman} 334648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 335648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartmanstatic int opticon_write_room(struct tty_struct *tty) 336648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman{ 337648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman struct usb_serial_port *port = tty->driver_data; 338648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman struct opticon_private *priv = usb_get_serial_data(port->serial); 339648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman unsigned long flags; 340648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 341648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 342648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 343648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman /* 344648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman * We really can take almost anything the user throws at us 345648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman * but let's pick a nice big number to tell the tty 346648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman * layer that we have lots of free space, unless we don't. 347648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman */ 348648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman spin_lock_irqsave(&priv->lock, flags); 349648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) { 350648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman spin_unlock_irqrestore(&priv->lock, flags); 351759f3634267a67ac90f3fa7fc06510dfd43b4e45Joe Perches dbg("%s - write limit hit", __func__); 352648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman return 0; 353648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman } 354648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman spin_unlock_irqrestore(&priv->lock, flags); 355648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 356648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman return 2048; 357648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman} 358648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman 35957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartmanstatic void opticon_throttle(struct tty_struct *tty) 36057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman{ 36157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct usb_serial_port *port = tty->driver_data; 36257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct opticon_private *priv = usb_get_serial_data(port->serial); 36357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman unsigned long flags; 36457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 36557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 36657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman spin_lock_irqsave(&priv->lock, flags); 36757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->throttled = true; 36857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman spin_unlock_irqrestore(&priv->lock, flags); 36957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman} 37057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 37157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 37257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartmanstatic void opticon_unthrottle(struct tty_struct *tty) 37357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman{ 37457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct usb_serial_port *port = tty->driver_data; 37557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct opticon_private *priv = usb_get_serial_data(port->serial); 37657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman unsigned long flags; 37788fa6590b30ef8c4d41923449ada104f915d8df8Oliver Neukum int result, was_throttled; 37857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 37957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 38057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 38157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman spin_lock_irqsave(&priv->lock, flags); 38257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->throttled = false; 38388fa6590b30ef8c4d41923449ada104f915d8df8Oliver Neukum was_throttled = priv->actually_throttled; 38457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->actually_throttled = false; 38557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman spin_unlock_irqrestore(&priv->lock, flags); 38657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 38788fa6590b30ef8c4d41923449ada104f915d8df8Oliver Neukum if (was_throttled) { 38888fa6590b30ef8c4d41923449ada104f915d8df8Oliver Neukum result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC); 38988fa6590b30ef8c4d41923449ada104f915d8df8Oliver Neukum if (result) 39088fa6590b30ef8c4d41923449ada104f915d8df8Oliver Neukum dev_err(&port->dev, 39188fa6590b30ef8c4d41923449ada104f915d8df8Oliver Neukum "%s - failed submitting read urb, error %d\n", 39257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman __func__, result); 39388fa6590b30ef8c4d41923449ada104f915d8df8Oliver Neukum } 39457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman} 39557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 39660b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int opticon_tiocmget(struct tty_struct *tty) 397faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman{ 398faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman struct usb_serial_port *port = tty->driver_data; 399faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman struct opticon_private *priv = usb_get_serial_data(port->serial); 400faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman unsigned long flags; 401faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman int result = 0; 402faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 403faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman dbg("%s - port %d", __func__, port->number); 404309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen if (!usb_get_intfdata(port->serial->interface)) 405309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen return -ENODEV; 406faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 407faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman spin_lock_irqsave(&priv->lock, flags); 408faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman if (priv->rts) 409309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen result |= TIOCM_RTS; 410309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen if (priv->cts) 411309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen result |= TIOCM_CTS; 412faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman spin_unlock_irqrestore(&priv->lock, flags); 413faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 414faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman dbg("%s - %x", __func__, result); 415faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman return result; 416faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman} 417faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 4184acfaf829dacb8f8170b439d30065e8d2cfdaac9Randy Dunlapstatic int opticon_tiocmset(struct tty_struct *tty, 419309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen unsigned int set, unsigned int clear) 420309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen{ 421309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen struct usb_serial_port *port = tty->driver_data; 422309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen struct opticon_private *priv = usb_get_serial_data(port->serial); 423309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen unsigned long flags; 424309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen bool rts; 425309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen bool changed = false; 426309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 427309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen if (!usb_get_intfdata(port->serial->interface)) 428309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen return -ENODEV; 429309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen /* We only support RTS so we only handle that */ 430309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen spin_lock_irqsave(&priv->lock, flags); 431309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 432309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen rts = priv->rts; 433309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen if (set & TIOCM_RTS) 434309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen priv->rts = true; 435309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen if (clear & TIOCM_RTS) 436309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen priv->rts = false; 437309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen changed = rts ^ priv->rts; 438309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen spin_unlock_irqrestore(&priv->lock, flags); 439309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 440309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen if (!changed) 441309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen return 0; 442309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 443309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen /* Send the new RTS state to the connected device */ 444309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen return send_control_msg(port, CONTROL_RTS, !rts); 445309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen} 446309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen 447faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartmanstatic int get_serial_info(struct opticon_private *priv, 448faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman struct serial_struct __user *serial) 449faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman{ 450faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman struct serial_struct tmp; 451faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 452faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman if (!serial) 453faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman return -EFAULT; 454faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 455faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman memset(&tmp, 0x00, sizeof(tmp)); 456faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 457faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman /* fake emulate a 16550 uart to make userspace code happy */ 458faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman tmp.type = PORT_16550A; 459faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman tmp.line = priv->serial->minor; 460faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman tmp.port = 0; 461faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman tmp.irq = 0; 462faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; 463faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman tmp.xmit_fifo_size = 1024; 464faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman tmp.baud_base = 9600; 465faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman tmp.close_delay = 5*HZ; 466faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman tmp.closing_wait = 30*HZ; 467faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 468faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman if (copy_to_user(serial, &tmp, sizeof(*serial))) 469faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman return -EFAULT; 470faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman return 0; 471faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman} 472faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 47300a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int opticon_ioctl(struct tty_struct *tty, 474faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman unsigned int cmd, unsigned long arg) 475faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman{ 476faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman struct usb_serial_port *port = tty->driver_data; 477faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman struct opticon_private *priv = usb_get_serial_data(port->serial); 478faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 479faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); 480faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 481faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman switch (cmd) { 482faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman case TIOCGSERIAL: 483faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman return get_serial_info(priv, 484faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman (struct serial_struct __user *)arg); 485faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman } 486faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 487faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman return -ENOIOCTLCMD; 488faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman} 489faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman 49057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartmanstatic int opticon_startup(struct usb_serial *serial) 49157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman{ 49257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct opticon_private *priv; 49357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct usb_host_interface *intf; 49457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman int i; 49557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman int retval = -ENOMEM; 49657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman bool bulk_in_found = false; 49757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 49857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman /* create our private serial structure */ 49957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv = kzalloc(sizeof(*priv), GFP_KERNEL); 50057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (priv == NULL) { 50157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); 50257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman return -ENOMEM; 50357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } 50457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman spin_lock_init(&priv->lock); 50557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->serial = serial; 50657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->port = serial->port[0]; 50757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->udev = serial->dev; 508309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen priv->outstanding_urbs = 0; /* Init the outstanding urbs */ 50957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 51057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman /* find our bulk endpoint */ 51157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman intf = serial->interface->altsetting; 51257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman for (i = 0; i < intf->desc.bNumEndpoints; ++i) { 51357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct usb_endpoint_descriptor *endpoint; 51457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 51557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman endpoint = &intf->endpoint[i].desc; 51657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (!usb_endpoint_is_bulk_in(endpoint)) 51757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman continue; 51857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 51957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->bulk_read_urb = usb_alloc_urb(0, GFP_KERNEL); 52057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (!priv->bulk_read_urb) { 52157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dev_err(&priv->udev->dev, "out of memory\n"); 52257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman goto error; 52357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } 52457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 52529cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto priv->buffer_size = usb_endpoint_maxp(endpoint) * 2; 52657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->bulk_in_buffer = kmalloc(priv->buffer_size, GFP_KERNEL); 52757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (!priv->bulk_in_buffer) { 52857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dev_err(&priv->udev->dev, "out of memory\n"); 52957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman goto error; 53057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } 53157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 53257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman priv->bulk_address = endpoint->bEndpointAddress; 53357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 53457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman bulk_in_found = true; 53557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman break; 53657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } 53757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 53857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman if (!bulk_in_found) { 53957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dev_err(&priv->udev->dev, 54057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman "Error - the proper endpoints were not found!\n"); 54157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman goto error; 54257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman } 54357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 54457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman usb_set_serial_data(serial, priv); 54557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman return 0; 54657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 54757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartmanerror: 54857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman usb_free_urb(priv->bulk_read_urb); 54957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman kfree(priv->bulk_in_buffer); 55057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman kfree(priv); 55157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman return retval; 55257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman} 55357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 554f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void opticon_disconnect(struct usb_serial *serial) 55557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman{ 55657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman struct opticon_private *priv = usb_get_serial_data(serial); 55757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 55857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman dbg("%s", __func__); 55957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 56057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman usb_kill_urb(priv->bulk_read_urb); 56157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman usb_free_urb(priv->bulk_read_urb); 562f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern} 563f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 564f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Sternstatic void opticon_release(struct usb_serial *serial) 565f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern{ 566f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern struct opticon_private *priv = usb_get_serial_data(serial); 567f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 568f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern dbg("%s", __func__); 569f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern 57057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman kfree(priv->bulk_in_buffer); 57157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman kfree(priv); 57257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman} 57357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 574d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukumstatic int opticon_suspend(struct usb_interface *intf, pm_message_t message) 575d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum{ 576d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum struct usb_serial *serial = usb_get_intfdata(intf); 577d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum struct opticon_private *priv = usb_get_serial_data(serial); 578d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum 579d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum usb_kill_urb(priv->bulk_read_urb); 580d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum return 0; 581d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum} 582d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum 583d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukumstatic int opticon_resume(struct usb_interface *intf) 584d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum{ 585d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum struct usb_serial *serial = usb_get_intfdata(intf); 586d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum struct opticon_private *priv = usb_get_serial_data(serial); 587d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum struct usb_serial_port *port = serial->port[0]; 588d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum int result; 589d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum 59082fc5943430e3cbf15033ed4186a73f90906345dAlan Cox mutex_lock(&port->port.mutex); 5912a0785ea375fe93cd480599bb40d0c837ff72a2eAlan Cox /* This is protected by the port mutex against close/open */ 5922a0785ea375fe93cd480599bb40d0c837ff72a2eAlan Cox if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) 593d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum result = usb_submit_urb(priv->bulk_read_urb, GFP_NOIO); 594d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum else 595d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum result = 0; 59682fc5943430e3cbf15033ed4186a73f90906345dAlan Cox mutex_unlock(&port->port.mutex); 597d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum return result; 598d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum} 59957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 60057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartmanstatic struct usb_driver opticon_driver = { 60157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .name = "opticon", 60257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .probe = usb_serial_probe, 60357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .disconnect = usb_serial_disconnect, 604d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum .suspend = opticon_suspend, 605d1c0713daea5d1d881ecc8707458ca6746031376Oliver Neukum .resume = opticon_resume, 60657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .id_table = id_table, 60757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman}; 60857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 60957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartmanstatic struct usb_serial_driver opticon_device = { 61057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .driver = { 61157262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .owner = THIS_MODULE, 61257262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .name = "opticon", 61357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman }, 61457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .id_table = id_table, 61557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .num_ports = 1, 61657262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .attach = opticon_startup, 61757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .open = opticon_open, 61857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .close = opticon_close, 619648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman .write = opticon_write, 620648d4e16567eae4c643bd2125e91128f06c0d3adGreg Kroah-Hartman .write_room = opticon_write_room, 621f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .disconnect = opticon_disconnect, 622f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .release = opticon_release, 62357262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .throttle = opticon_throttle, 62457262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman .unthrottle = opticon_unthrottle, 625faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman .ioctl = opticon_ioctl, 626faac64ad9c7b1aa56a10be6b5f9b813789e81dfdGreg Kroah-Hartman .tiocmget = opticon_tiocmget, 627309a057932ab20057da9fe4cb18fb61803dfc924Martin Jansen .tiocmset = opticon_tiocmset, 62857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman}; 62957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 630f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = { 631f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern &opticon_device, NULL 632f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern}; 633f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern 634e206b7f831da365a38b22f72ba42db288db71c65Greg Kroah-Hartmanmodule_usb_serial_driver(opticon_driver, serial_drivers); 63557262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 636309a057932ab20057da9fe4cb18fb61803dfc924Martin JansenMODULE_DESCRIPTION(DRIVER_DESC); 63757262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-HartmanMODULE_LICENSE("GPL"); 63857262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartman 63957262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-Hartmanmodule_param(debug, bool, S_IRUGO | S_IWUSR); 64057262b82d601c5ca8e3db219aebd332950f62ba1Greg Kroah-HartmanMODULE_PARM_DESC(debug, "Debug enabled or not"); 641