18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Opticon USB barcode to serial driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 - 2012 Johan Hovold <jhovold@gmail.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2011 Martin Jansen <martin.jansen@opticon.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2008 - 2009 Greg Kroah-Hartman <gregkh@suse.de> 88c2ecf20Sopenharmony_ci * Copyright (C) 2008 - 2009 Novell Inc. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/tty.h> 138c2ecf20Sopenharmony_ci#include <linux/tty_driver.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 168c2ecf20Sopenharmony_ci#include <linux/serial.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/usb.h> 198c2ecf20Sopenharmony_ci#include <linux/usb/serial.h> 208c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define CONTROL_RTS 0x02 238c2ecf20Sopenharmony_ci#define RESEND_CTS_STATE 0x03 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* max number of write urbs in flight */ 268c2ecf20Sopenharmony_ci#define URB_UPPER_LIMIT 8 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* This driver works for the Opticon 1D barcode reader 298c2ecf20Sopenharmony_ci * an examples of 1D barcode types are EAN, UPC, Code39, IATA etc.. */ 308c2ecf20Sopenharmony_ci#define DRIVER_DESC "Opticon USB barcode to serial driver (1D)" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table[] = { 338c2ecf20Sopenharmony_ci { USB_DEVICE(0x065a, 0x0009) }, 348c2ecf20Sopenharmony_ci { }, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* This structure holds all of the individual device information */ 398c2ecf20Sopenharmony_cistruct opticon_private { 408c2ecf20Sopenharmony_ci spinlock_t lock; /* protects the following flags */ 418c2ecf20Sopenharmony_ci bool rts; 428c2ecf20Sopenharmony_ci bool cts; 438c2ecf20Sopenharmony_ci int outstanding_urbs; 448c2ecf20Sopenharmony_ci int outstanding_bytes; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci struct usb_anchor anchor; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void opticon_process_data_packet(struct usb_serial_port *port, 518c2ecf20Sopenharmony_ci const unsigned char *buf, size_t len) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci tty_insert_flip_string(&port->port, buf, len); 548c2ecf20Sopenharmony_ci tty_flip_buffer_push(&port->port); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void opticon_process_status_packet(struct usb_serial_port *port, 588c2ecf20Sopenharmony_ci const unsigned char *buf, size_t len) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct opticon_private *priv = usb_get_serial_port_data(port); 618c2ecf20Sopenharmony_ci unsigned long flags; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 648c2ecf20Sopenharmony_ci if (buf[0] == 0x00) 658c2ecf20Sopenharmony_ci priv->cts = false; 668c2ecf20Sopenharmony_ci else 678c2ecf20Sopenharmony_ci priv->cts = true; 688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void opticon_process_read_urb(struct urb *urb) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 748c2ecf20Sopenharmony_ci const unsigned char *hdr = urb->transfer_buffer; 758c2ecf20Sopenharmony_ci const unsigned char *data = hdr + 2; 768c2ecf20Sopenharmony_ci size_t data_len = urb->actual_length - 2; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (urb->actual_length <= 2) { 798c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "malformed packet received: %d bytes\n", 808c2ecf20Sopenharmony_ci urb->actual_length); 818c2ecf20Sopenharmony_ci return; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci /* 848c2ecf20Sopenharmony_ci * Data from the device comes with a 2 byte header: 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * <0x00><0x00>data... 878c2ecf20Sopenharmony_ci * This is real data to be sent to the tty layer 888c2ecf20Sopenharmony_ci * <0x00><0x01>level 898c2ecf20Sopenharmony_ci * This is a CTS level change, the third byte is the CTS 908c2ecf20Sopenharmony_ci * value (0 for low, 1 for high). 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci if ((hdr[0] == 0x00) && (hdr[1] == 0x00)) { 938c2ecf20Sopenharmony_ci opticon_process_data_packet(port, data, data_len); 948c2ecf20Sopenharmony_ci } else if ((hdr[0] == 0x00) && (hdr[1] == 0x01)) { 958c2ecf20Sopenharmony_ci opticon_process_status_packet(port, data, data_len); 968c2ecf20Sopenharmony_ci } else { 978c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "unknown packet received: %02x %02x\n", 988c2ecf20Sopenharmony_ci hdr[0], hdr[1]); 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int send_control_msg(struct usb_serial_port *port, u8 requesttype, 1038c2ecf20Sopenharmony_ci u8 val) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 1068c2ecf20Sopenharmony_ci int retval; 1078c2ecf20Sopenharmony_ci u8 *buffer; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci buffer = kzalloc(1, GFP_KERNEL); 1108c2ecf20Sopenharmony_ci if (!buffer) 1118c2ecf20Sopenharmony_ci return -ENOMEM; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci buffer[0] = val; 1148c2ecf20Sopenharmony_ci /* Send the message to the vendor control endpoint 1158c2ecf20Sopenharmony_ci * of the connected device */ 1168c2ecf20Sopenharmony_ci retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 1178c2ecf20Sopenharmony_ci requesttype, 1188c2ecf20Sopenharmony_ci USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, 1198c2ecf20Sopenharmony_ci 0, 0, buffer, 1, USB_CTRL_SET_TIMEOUT); 1208c2ecf20Sopenharmony_ci kfree(buffer); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (retval < 0) 1238c2ecf20Sopenharmony_ci return retval; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct opticon_private *priv = usb_get_serial_port_data(port); 1318c2ecf20Sopenharmony_ci unsigned long flags; 1328c2ecf20Sopenharmony_ci int res; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 1358c2ecf20Sopenharmony_ci priv->rts = false; 1368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* Clear RTS line */ 1398c2ecf20Sopenharmony_ci send_control_msg(port, CONTROL_RTS, 0); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* clear the halt status of the endpoint */ 1428c2ecf20Sopenharmony_ci usb_clear_halt(port->serial->dev, port->read_urb->pipe); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci res = usb_serial_generic_open(tty, port); 1458c2ecf20Sopenharmony_ci if (res) 1468c2ecf20Sopenharmony_ci return res; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Request CTS line state, sometimes during opening the current 1498c2ecf20Sopenharmony_ci * CTS state can be missed. */ 1508c2ecf20Sopenharmony_ci send_control_msg(port, RESEND_CTS_STATE, 1); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return res; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void opticon_close(struct usb_serial_port *port) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct opticon_private *priv = usb_get_serial_port_data(port); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&priv->anchor); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci usb_serial_generic_close(port); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void opticon_write_control_callback(struct urb *urb) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 1678c2ecf20Sopenharmony_ci struct opticon_private *priv = usb_get_serial_port_data(port); 1688c2ecf20Sopenharmony_ci int status = urb->status; 1698c2ecf20Sopenharmony_ci unsigned long flags; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* free up the transfer buffer, as usb_free_urb() does not do this */ 1728c2ecf20Sopenharmony_ci kfree(urb->transfer_buffer); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* setup packet may be set if we're using it for writing */ 1758c2ecf20Sopenharmony_ci kfree(urb->setup_packet); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (status) 1788c2ecf20Sopenharmony_ci dev_dbg(&port->dev, 1798c2ecf20Sopenharmony_ci "%s - non-zero urb status received: %d\n", 1808c2ecf20Sopenharmony_ci __func__, status); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 1838c2ecf20Sopenharmony_ci --priv->outstanding_urbs; 1848c2ecf20Sopenharmony_ci priv->outstanding_bytes -= urb->transfer_buffer_length; 1858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci usb_serial_port_softint(port); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, 1918c2ecf20Sopenharmony_ci const unsigned char *buf, int count) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct opticon_private *priv = usb_get_serial_port_data(port); 1948c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 1958c2ecf20Sopenharmony_ci struct urb *urb; 1968c2ecf20Sopenharmony_ci unsigned char *buffer; 1978c2ecf20Sopenharmony_ci unsigned long flags; 1988c2ecf20Sopenharmony_ci struct usb_ctrlrequest *dr; 1998c2ecf20Sopenharmony_ci int ret = -ENOMEM; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 2028c2ecf20Sopenharmony_ci if (priv->outstanding_urbs > URB_UPPER_LIMIT) { 2038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2048c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - write limit hit\n", __func__); 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci priv->outstanding_urbs++; 2088c2ecf20Sopenharmony_ci priv->outstanding_bytes += count; 2098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci buffer = kmalloc(count, GFP_ATOMIC); 2128c2ecf20Sopenharmony_ci if (!buffer) 2138c2ecf20Sopenharmony_ci goto error_no_buffer; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 2168c2ecf20Sopenharmony_ci if (!urb) 2178c2ecf20Sopenharmony_ci goto error_no_urb; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci memcpy(buffer, buf, count); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, count, buffer); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* The connected devices do not have a bulk write endpoint, 2248c2ecf20Sopenharmony_ci * to transmit data to de barcode device the control endpoint is used */ 2258c2ecf20Sopenharmony_ci dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); 2268c2ecf20Sopenharmony_ci if (!dr) 2278c2ecf20Sopenharmony_ci goto error_no_dr; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci dr->bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT; 2308c2ecf20Sopenharmony_ci dr->bRequest = 0x01; 2318c2ecf20Sopenharmony_ci dr->wValue = 0; 2328c2ecf20Sopenharmony_ci dr->wIndex = 0; 2338c2ecf20Sopenharmony_ci dr->wLength = cpu_to_le16(count); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci usb_fill_control_urb(urb, serial->dev, 2368c2ecf20Sopenharmony_ci usb_sndctrlpipe(serial->dev, 0), 2378c2ecf20Sopenharmony_ci (unsigned char *)dr, buffer, count, 2388c2ecf20Sopenharmony_ci opticon_write_control_callback, port); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci usb_anchor_urb(urb, &priv->anchor); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* send it down the pipe */ 2438c2ecf20Sopenharmony_ci ret = usb_submit_urb(urb, GFP_ATOMIC); 2448c2ecf20Sopenharmony_ci if (ret) { 2458c2ecf20Sopenharmony_ci dev_err(&port->dev, "failed to submit write urb: %d\n", ret); 2468c2ecf20Sopenharmony_ci usb_unanchor_urb(urb); 2478c2ecf20Sopenharmony_ci goto error; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* we are done with this urb, so let the host driver 2518c2ecf20Sopenharmony_ci * really free it when it is finished with it */ 2528c2ecf20Sopenharmony_ci usb_free_urb(urb); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return count; 2558c2ecf20Sopenharmony_cierror: 2568c2ecf20Sopenharmony_ci kfree(dr); 2578c2ecf20Sopenharmony_cierror_no_dr: 2588c2ecf20Sopenharmony_ci usb_free_urb(urb); 2598c2ecf20Sopenharmony_cierror_no_urb: 2608c2ecf20Sopenharmony_ci kfree(buffer); 2618c2ecf20Sopenharmony_cierror_no_buffer: 2628c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 2638c2ecf20Sopenharmony_ci --priv->outstanding_urbs; 2648c2ecf20Sopenharmony_ci priv->outstanding_bytes -= count; 2658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return ret; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int opticon_write_room(struct tty_struct *tty) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 2738c2ecf20Sopenharmony_ci struct opticon_private *priv = usb_get_serial_port_data(port); 2748c2ecf20Sopenharmony_ci unsigned long flags; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* 2778c2ecf20Sopenharmony_ci * We really can take almost anything the user throws at us 2788c2ecf20Sopenharmony_ci * but let's pick a nice big number to tell the tty 2798c2ecf20Sopenharmony_ci * layer that we have lots of free space, unless we don't. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 2828c2ecf20Sopenharmony_ci if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) { 2838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2848c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - write limit hit\n", __func__); 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return 2048; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int opticon_chars_in_buffer(struct tty_struct *tty) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 2958c2ecf20Sopenharmony_ci struct opticon_private *priv = usb_get_serial_port_data(port); 2968c2ecf20Sopenharmony_ci unsigned long flags; 2978c2ecf20Sopenharmony_ci int count; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 3008c2ecf20Sopenharmony_ci count = priv->outstanding_bytes; 3018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return count; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int opticon_tiocmget(struct tty_struct *tty) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 3098c2ecf20Sopenharmony_ci struct opticon_private *priv = usb_get_serial_port_data(port); 3108c2ecf20Sopenharmony_ci unsigned long flags; 3118c2ecf20Sopenharmony_ci int result = 0; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 3148c2ecf20Sopenharmony_ci if (priv->rts) 3158c2ecf20Sopenharmony_ci result |= TIOCM_RTS; 3168c2ecf20Sopenharmony_ci if (priv->cts) 3178c2ecf20Sopenharmony_ci result |= TIOCM_CTS; 3188c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - %x\n", __func__, result); 3218c2ecf20Sopenharmony_ci return result; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic int opticon_tiocmset(struct tty_struct *tty, 3258c2ecf20Sopenharmony_ci unsigned int set, unsigned int clear) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 3288c2ecf20Sopenharmony_ci struct opticon_private *priv = usb_get_serial_port_data(port); 3298c2ecf20Sopenharmony_ci unsigned long flags; 3308c2ecf20Sopenharmony_ci bool rts; 3318c2ecf20Sopenharmony_ci bool changed = false; 3328c2ecf20Sopenharmony_ci int ret; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* We only support RTS so we only handle that */ 3358c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci rts = priv->rts; 3388c2ecf20Sopenharmony_ci if (set & TIOCM_RTS) 3398c2ecf20Sopenharmony_ci priv->rts = true; 3408c2ecf20Sopenharmony_ci if (clear & TIOCM_RTS) 3418c2ecf20Sopenharmony_ci priv->rts = false; 3428c2ecf20Sopenharmony_ci changed = rts ^ priv->rts; 3438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (!changed) 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci ret = send_control_msg(port, CONTROL_RTS, !rts); 3498c2ecf20Sopenharmony_ci if (ret) 3508c2ecf20Sopenharmony_ci return usb_translate_errors(ret); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int get_serial_info(struct tty_struct *tty, 3568c2ecf20Sopenharmony_ci struct serial_struct *ss) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* fake emulate a 16550 uart to make userspace code happy */ 3618c2ecf20Sopenharmony_ci ss->type = PORT_16550A; 3628c2ecf20Sopenharmony_ci ss->line = port->minor; 3638c2ecf20Sopenharmony_ci ss->port = 0; 3648c2ecf20Sopenharmony_ci ss->irq = 0; 3658c2ecf20Sopenharmony_ci ss->xmit_fifo_size = 1024; 3668c2ecf20Sopenharmony_ci ss->baud_base = 9600; 3678c2ecf20Sopenharmony_ci ss->close_delay = 5*HZ; 3688c2ecf20Sopenharmony_ci ss->closing_wait = 30*HZ; 3698c2ecf20Sopenharmony_ci return 0; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int opticon_port_probe(struct usb_serial_port *port) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct opticon_private *priv; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 3778c2ecf20Sopenharmony_ci if (!priv) 3788c2ecf20Sopenharmony_ci return -ENOMEM; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 3818c2ecf20Sopenharmony_ci init_usb_anchor(&priv->anchor); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci usb_set_serial_port_data(port, priv); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic int opticon_port_remove(struct usb_serial_port *port) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct opticon_private *priv = usb_get_serial_port_data(port); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci kfree(priv); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic struct usb_serial_driver opticon_device = { 3988c2ecf20Sopenharmony_ci .driver = { 3998c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4008c2ecf20Sopenharmony_ci .name = "opticon", 4018c2ecf20Sopenharmony_ci }, 4028c2ecf20Sopenharmony_ci .id_table = id_table, 4038c2ecf20Sopenharmony_ci .num_ports = 1, 4048c2ecf20Sopenharmony_ci .num_bulk_in = 1, 4058c2ecf20Sopenharmony_ci .bulk_in_size = 256, 4068c2ecf20Sopenharmony_ci .port_probe = opticon_port_probe, 4078c2ecf20Sopenharmony_ci .port_remove = opticon_port_remove, 4088c2ecf20Sopenharmony_ci .open = opticon_open, 4098c2ecf20Sopenharmony_ci .close = opticon_close, 4108c2ecf20Sopenharmony_ci .write = opticon_write, 4118c2ecf20Sopenharmony_ci .write_room = opticon_write_room, 4128c2ecf20Sopenharmony_ci .chars_in_buffer = opticon_chars_in_buffer, 4138c2ecf20Sopenharmony_ci .throttle = usb_serial_generic_throttle, 4148c2ecf20Sopenharmony_ci .unthrottle = usb_serial_generic_unthrottle, 4158c2ecf20Sopenharmony_ci .get_serial = get_serial_info, 4168c2ecf20Sopenharmony_ci .tiocmget = opticon_tiocmget, 4178c2ecf20Sopenharmony_ci .tiocmset = opticon_tiocmset, 4188c2ecf20Sopenharmony_ci .process_read_urb = opticon_process_read_urb, 4198c2ecf20Sopenharmony_ci}; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 4228c2ecf20Sopenharmony_ci &opticon_device, NULL 4238c2ecf20Sopenharmony_ci}; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 4288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 429