.. | .. |
---|
| 1 | +/* |
---|
| 2 | + * This program is free software; you can redistribute it and/or modify |
---|
| 3 | + * it under the terms of the GNU General Public License as published by |
---|
| 4 | + * the Free Software Foundation; either version 2 of the License, or |
---|
| 5 | + * (at your option) any later version. |
---|
| 6 | + * |
---|
| 7 | + * This program is distributed in the hope that it will be useful, |
---|
| 8 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 9 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 10 | + * GNU General Public License for more details. |
---|
| 11 | + * |
---|
| 12 | + * You should have received a copy of the GNU General Public License |
---|
| 13 | + * along with this program; if not, write to the Free Software |
---|
| 14 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 15 | + */ |
---|
| 16 | + |
---|
| 17 | + /* |
---|
| 18 | + * Copyright (c) 2015 Exar Corporation, Inc. |
---|
| 19 | + * |
---|
| 20 | + * This driver will work with any USB UART function in these Exar devices: |
---|
| 21 | + * XR21V1410/1412/1414 |
---|
| 22 | + * XR21B1411 |
---|
| 23 | + * XR21B1420/1422/1424 |
---|
| 24 | + * XR22801/802/804 |
---|
| 25 | + * |
---|
| 26 | + * The driver has been tested on various kernel versions from 3.6.x to 3.17.x. |
---|
| 27 | + * This driver may work on newer versions as well. There is a different driver available |
---|
| 28 | + * from www.exar.com that will work with kernel versions 2.6.18 to 3.4.x. |
---|
| 29 | + * |
---|
| 30 | + * ChangeLog: |
---|
| 31 | + * Version 1B - Initial released version. |
---|
| 32 | + * Version 1C - Add 9-bit mode support |
---|
| 33 | + */ |
---|
| 34 | + |
---|
| 35 | +//#undef DEBUG |
---|
| 36 | +#undef VERBOSE_DEBUG |
---|
| 37 | + |
---|
| 38 | +#include <linux/kernel.h> |
---|
| 39 | +#include <linux/errno.h> |
---|
| 40 | +#include <linux/init.h> |
---|
| 41 | +#include <linux/slab.h> |
---|
| 42 | +#include <linux/tty.h> |
---|
| 43 | +#include <linux/serial.h> |
---|
| 44 | +#include <linux/tty_driver.h> |
---|
| 45 | +#include <linux/tty_flip.h> |
---|
| 46 | +#include <linux/module.h> |
---|
| 47 | +#include <linux/mutex.h> |
---|
| 48 | +#include <linux/uaccess.h> |
---|
| 49 | +#include <linux/usb.h> |
---|
| 50 | +#include <linux/usb/cdc.h> |
---|
| 51 | +#include <asm/byteorder.h> |
---|
| 52 | +#include <asm/unaligned.h> |
---|
| 53 | +#include <linux/list.h> |
---|
| 54 | +#include "linux/version.h" |
---|
| 55 | + |
---|
| 56 | +#include "xr_usb_serial_common.h" |
---|
| 57 | +#include "xr_usb_serial_ioctl.h" |
---|
| 58 | + |
---|
| 59 | + |
---|
| 60 | +#define DRIVER_AUTHOR "<uarttechsupport@exar.com>" |
---|
| 61 | +#define DRIVER_DESC "Exar USB UART (serial port) driver" |
---|
| 62 | + |
---|
| 63 | +static struct usb_driver xr_usb_serial_driver; |
---|
| 64 | +static struct tty_driver *xr_usb_serial_tty_driver; |
---|
| 65 | +static struct xr_usb_serial *xr_usb_serial_table[XR_USB_SERIAL_TTY_MINORS]; |
---|
| 66 | + |
---|
| 67 | +static DEFINE_MUTEX(xr_usb_serial_table_lock); |
---|
| 68 | + |
---|
| 69 | +static void xr_usb_serial_tty_set_termios(struct tty_struct *tty, |
---|
| 70 | + struct ktermios *termios_old); |
---|
| 71 | +/* |
---|
| 72 | + * xr_usb_serial_table accessors |
---|
| 73 | + */ |
---|
| 74 | + |
---|
| 75 | +/* |
---|
| 76 | + * Look up an XR_USB_SERIAL structure by index. If found and not disconnected, increment |
---|
| 77 | + * its refcount and return it with its mutex held. |
---|
| 78 | + */ |
---|
| 79 | +static struct xr_usb_serial *xr_usb_serial_get_by_index(unsigned index) |
---|
| 80 | +{ |
---|
| 81 | + struct xr_usb_serial *xr_usb_serial; |
---|
| 82 | + |
---|
| 83 | + mutex_lock(&xr_usb_serial_table_lock); |
---|
| 84 | + xr_usb_serial = xr_usb_serial_table[index]; |
---|
| 85 | + if (xr_usb_serial) { |
---|
| 86 | + mutex_lock(&xr_usb_serial->mutex); |
---|
| 87 | + if (xr_usb_serial->disconnected) { |
---|
| 88 | + mutex_unlock(&xr_usb_serial->mutex); |
---|
| 89 | + xr_usb_serial = NULL; |
---|
| 90 | + } else { |
---|
| 91 | + tty_port_get(&xr_usb_serial->port); |
---|
| 92 | + mutex_unlock(&xr_usb_serial->mutex); |
---|
| 93 | + } |
---|
| 94 | + } |
---|
| 95 | + mutex_unlock(&xr_usb_serial_table_lock); |
---|
| 96 | + return xr_usb_serial; |
---|
| 97 | +} |
---|
| 98 | + |
---|
| 99 | +/* |
---|
| 100 | + * Try to find an available minor number and if found, associate it with 'xr_usb_serial'. |
---|
| 101 | + */ |
---|
| 102 | +static int xr_usb_serial_alloc_minor(struct xr_usb_serial *xr_usb_serial) |
---|
| 103 | +{ |
---|
| 104 | + int minor; |
---|
| 105 | + |
---|
| 106 | + mutex_lock(&xr_usb_serial_table_lock); |
---|
| 107 | + for (minor = 0; minor < XR_USB_SERIAL_TTY_MINORS; minor++) { |
---|
| 108 | + if (!xr_usb_serial_table[minor]) { |
---|
| 109 | + xr_usb_serial_table[minor] = xr_usb_serial; |
---|
| 110 | + break; |
---|
| 111 | + } |
---|
| 112 | + } |
---|
| 113 | + mutex_unlock(&xr_usb_serial_table_lock); |
---|
| 114 | + |
---|
| 115 | + return minor; |
---|
| 116 | +} |
---|
| 117 | + |
---|
| 118 | +/* Release the minor number associated with 'xr_usb_serial'. */ |
---|
| 119 | +static void xr_usb_serial_release_minor(struct xr_usb_serial *xr_usb_serial) |
---|
| 120 | +{ |
---|
| 121 | + mutex_lock(&xr_usb_serial_table_lock); |
---|
| 122 | + xr_usb_serial_table[xr_usb_serial->minor] = NULL; |
---|
| 123 | + mutex_unlock(&xr_usb_serial_table_lock); |
---|
| 124 | +} |
---|
| 125 | + |
---|
| 126 | +/* |
---|
| 127 | + * Functions for XR_USB_SERIAL control messages. |
---|
| 128 | + */ |
---|
| 129 | + |
---|
| 130 | +static int xr_usb_serial_ctrl_msg(struct xr_usb_serial *xr_usb_serial, int request, int value, |
---|
| 131 | + void *buf, int len) |
---|
| 132 | +{ |
---|
| 133 | + int retval = usb_control_msg(xr_usb_serial->dev, usb_sndctrlpipe(xr_usb_serial->dev, 0), |
---|
| 134 | + request, USB_RT_XR_USB_SERIAL, value, |
---|
| 135 | + xr_usb_serial->control->altsetting[0].desc.bInterfaceNumber, |
---|
| 136 | + buf, len, 5000); |
---|
| 137 | + dev_dbg(&xr_usb_serial->control->dev, |
---|
| 138 | + "%s - rq 0x%02x, val %#x, len %#x, result %d\n", |
---|
| 139 | + __func__, request, value, len, retval); |
---|
| 140 | + return retval < 0 ? retval : 0; |
---|
| 141 | +} |
---|
| 142 | + |
---|
| 143 | +#include "xr_usb_serial_hal.c" |
---|
| 144 | + |
---|
| 145 | + |
---|
| 146 | +/* |
---|
| 147 | + * Write buffer management. |
---|
| 148 | + * All of these assume proper locks taken by the caller. |
---|
| 149 | + */ |
---|
| 150 | + |
---|
| 151 | +static int xr_usb_serial_wb_alloc(struct xr_usb_serial *xr_usb_serial) |
---|
| 152 | +{ |
---|
| 153 | + int i, wbn; |
---|
| 154 | + struct xr_usb_serial_wb *wb; |
---|
| 155 | + |
---|
| 156 | + wbn = 0; |
---|
| 157 | + i = 0; |
---|
| 158 | + for (;;) { |
---|
| 159 | + wb = &xr_usb_serial->wb[wbn]; |
---|
| 160 | + if (!wb->use) { |
---|
| 161 | + wb->use = 1; |
---|
| 162 | + return wbn; |
---|
| 163 | + } |
---|
| 164 | + wbn = (wbn + 1) % XR_USB_SERIAL_NW; |
---|
| 165 | + if (++i >= XR_USB_SERIAL_NW) |
---|
| 166 | + return -1; |
---|
| 167 | + } |
---|
| 168 | +} |
---|
| 169 | + |
---|
| 170 | +static int xr_usb_serial_wb_is_avail(struct xr_usb_serial *xr_usb_serial) |
---|
| 171 | +{ |
---|
| 172 | + int i, n; |
---|
| 173 | + unsigned long flags; |
---|
| 174 | + |
---|
| 175 | + n = XR_USB_SERIAL_NW; |
---|
| 176 | + spin_lock_irqsave(&xr_usb_serial->write_lock, flags); |
---|
| 177 | + for (i = 0; i < XR_USB_SERIAL_NW; i++) |
---|
| 178 | + n -= xr_usb_serial->wb[i].use; |
---|
| 179 | + spin_unlock_irqrestore(&xr_usb_serial->write_lock, flags); |
---|
| 180 | + return n; |
---|
| 181 | +} |
---|
| 182 | + |
---|
| 183 | +/* |
---|
| 184 | + * Finish write. Caller must hold xr_usb_serial->write_lock |
---|
| 185 | + */ |
---|
| 186 | +static void xr_usb_serial_write_done(struct xr_usb_serial *xr_usb_serial, struct xr_usb_serial_wb *wb) |
---|
| 187 | +{ |
---|
| 188 | + wb->use = 0; |
---|
| 189 | + xr_usb_serial->transmitting--; |
---|
| 190 | + usb_autopm_put_interface_async(xr_usb_serial->control); |
---|
| 191 | +} |
---|
| 192 | + |
---|
| 193 | +/* |
---|
| 194 | + * Poke write. |
---|
| 195 | + * |
---|
| 196 | + * the caller is responsible for locking |
---|
| 197 | + */ |
---|
| 198 | + |
---|
| 199 | +static int xr_usb_serial_start_wb(struct xr_usb_serial *xr_usb_serial, struct xr_usb_serial_wb *wb) |
---|
| 200 | +{ |
---|
| 201 | + int rc; |
---|
| 202 | + |
---|
| 203 | + xr_usb_serial->transmitting++; |
---|
| 204 | + |
---|
| 205 | + wb->urb->transfer_buffer = wb->buf; |
---|
| 206 | + wb->urb->transfer_dma = wb->dmah; |
---|
| 207 | + wb->urb->transfer_buffer_length = wb->len; |
---|
| 208 | + wb->urb->dev = xr_usb_serial->dev; |
---|
| 209 | + |
---|
| 210 | + rc = usb_submit_urb(wb->urb, GFP_ATOMIC); |
---|
| 211 | + if (rc < 0) { |
---|
| 212 | + dev_err(&xr_usb_serial->data->dev, |
---|
| 213 | + "%s - usb_submit_urb(write bulk) failed: %d\n", |
---|
| 214 | + __func__, rc); |
---|
| 215 | + xr_usb_serial_write_done(xr_usb_serial, wb); |
---|
| 216 | + } |
---|
| 217 | + return rc; |
---|
| 218 | +} |
---|
| 219 | + |
---|
| 220 | +/* |
---|
| 221 | + * attributes exported through sysfs |
---|
| 222 | + */ |
---|
| 223 | +static ssize_t show_caps |
---|
| 224 | +(struct device *dev, struct device_attribute *attr, char *buf) |
---|
| 225 | +{ |
---|
| 226 | + struct usb_interface *intf = to_usb_interface(dev); |
---|
| 227 | + struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf); |
---|
| 228 | + |
---|
| 229 | + return sprintf(buf, "%d", xr_usb_serial->ctrl_caps); |
---|
| 230 | +} |
---|
| 231 | +static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL); |
---|
| 232 | + |
---|
| 233 | +static ssize_t show_country_codes |
---|
| 234 | +(struct device *dev, struct device_attribute *attr, char *buf) |
---|
| 235 | +{ |
---|
| 236 | + struct usb_interface *intf = to_usb_interface(dev); |
---|
| 237 | + struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf); |
---|
| 238 | + |
---|
| 239 | + memcpy(buf, xr_usb_serial->country_codes, xr_usb_serial->country_code_size); |
---|
| 240 | + return xr_usb_serial->country_code_size; |
---|
| 241 | +} |
---|
| 242 | + |
---|
| 243 | +static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL); |
---|
| 244 | + |
---|
| 245 | +static ssize_t show_country_rel_date |
---|
| 246 | +(struct device *dev, struct device_attribute *attr, char *buf) |
---|
| 247 | +{ |
---|
| 248 | + struct usb_interface *intf = to_usb_interface(dev); |
---|
| 249 | + struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf); |
---|
| 250 | + |
---|
| 251 | + return sprintf(buf, "%d", xr_usb_serial->country_rel_date); |
---|
| 252 | +} |
---|
| 253 | + |
---|
| 254 | +static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL); |
---|
| 255 | +/* |
---|
| 256 | + * Interrupt handlers for various XR_USB_SERIAL device responses |
---|
| 257 | + */ |
---|
| 258 | + |
---|
| 259 | +/* control interface reports status changes with "interrupt" transfers */ |
---|
| 260 | +static void xr_usb_serial_ctrl_irq(struct urb *urb) |
---|
| 261 | +{ |
---|
| 262 | + struct xr_usb_serial *xr_usb_serial = urb->context; |
---|
| 263 | + struct usb_cdc_notification *dr = urb->transfer_buffer; |
---|
| 264 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0) |
---|
| 265 | +#else |
---|
| 266 | + struct tty_struct *tty; |
---|
| 267 | +#endif |
---|
| 268 | + unsigned char *data; |
---|
| 269 | + int newctrl; |
---|
| 270 | + int retval; |
---|
| 271 | + int status = urb->status; |
---|
| 272 | + int i; |
---|
| 273 | + unsigned char *p; |
---|
| 274 | + |
---|
| 275 | + switch (status) { |
---|
| 276 | + case 0: |
---|
| 277 | + p = (unsigned char *)(urb->transfer_buffer); |
---|
| 278 | + for(i=0;i<urb->actual_length;i++) |
---|
| 279 | + { |
---|
| 280 | + //dev_dbg(&xr_usb_serial->control->dev,"0x%02x\n",p[i]); |
---|
| 281 | + } |
---|
| 282 | + /* success */ |
---|
| 283 | + break; |
---|
| 284 | + case -ECONNRESET: |
---|
| 285 | + case -ENOENT: |
---|
| 286 | + case -ESHUTDOWN: |
---|
| 287 | + /* this urb is terminated, clean up */ |
---|
| 288 | + /* by fuyingzhe 2021.01.08 |
---|
| 289 | + dev_dbg(&xr_usb_serial->control->dev, |
---|
| 290 | + "%s - urb shutting down with status: %d\n", |
---|
| 291 | + __func__, status); |
---|
| 292 | + */ |
---|
| 293 | + return; |
---|
| 294 | + default: |
---|
| 295 | + dev_dbg(&xr_usb_serial->control->dev, |
---|
| 296 | + "%s - nonzero urb status received: %d\n", |
---|
| 297 | + __func__, status); |
---|
| 298 | + goto exit; |
---|
| 299 | + } |
---|
| 300 | + |
---|
| 301 | + usb_mark_last_busy(xr_usb_serial->dev); |
---|
| 302 | + |
---|
| 303 | + data = (unsigned char *)(dr + 1); |
---|
| 304 | + switch (dr->bNotificationType) { |
---|
| 305 | + case USB_CDC_NOTIFY_NETWORK_CONNECTION: |
---|
| 306 | + dev_dbg(&xr_usb_serial->control->dev, "%s - network connection: %d\n", |
---|
| 307 | + __func__, dr->wValue); |
---|
| 308 | + break; |
---|
| 309 | + |
---|
| 310 | + case USB_CDC_NOTIFY_SERIAL_STATE: |
---|
| 311 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0) |
---|
| 312 | + newctrl = get_unaligned_le16(data); |
---|
| 313 | + if (!xr_usb_serial->clocal && (xr_usb_serial->ctrlin & ~newctrl & XR_USB_SERIAL_CTRL_DCD)) { |
---|
| 314 | + dev_dbg(&xr_usb_serial->control->dev, "%s - calling hangup\n", |
---|
| 315 | + __func__); |
---|
| 316 | + tty_port_tty_hangup(&xr_usb_serial->port, false); |
---|
| 317 | + } |
---|
| 318 | +#else |
---|
| 319 | + tty = tty_port_tty_get(&xr_usb_serial->port); |
---|
| 320 | + newctrl = get_unaligned_le16(data); |
---|
| 321 | + if (tty) |
---|
| 322 | + { |
---|
| 323 | + if (!xr_usb_serial->clocal && |
---|
| 324 | + (xr_usb_serial->ctrlin & ~newctrl & XR_USB_SERIAL_CTRL_DCD)) { |
---|
| 325 | + dev_dbg(&xr_usb_serial->control->dev, |
---|
| 326 | + "%s - calling hangup\n", __func__); |
---|
| 327 | + tty_hangup(tty); |
---|
| 328 | + } |
---|
| 329 | + tty_kref_put(tty); |
---|
| 330 | + } |
---|
| 331 | +#endif |
---|
| 332 | + xr_usb_serial->ctrlin = newctrl; |
---|
| 333 | + |
---|
| 334 | + /*dev_dbg(&xr_usb_serial->control->dev, |
---|
| 335 | + "%s - input control lines: dcd%c dsr%c break%c " |
---|
| 336 | + "ring%c framing%c parity%c overrun%c\n", |
---|
| 337 | + __func__, |
---|
| 338 | + xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_DCD ? '+' : '-', |
---|
| 339 | + xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_DSR ? '+' : '-', |
---|
| 340 | + xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_BRK ? '+' : '-', |
---|
| 341 | + xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_RI ? '+' : '-', |
---|
| 342 | + xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_FRAMING ? '+' : '-', |
---|
| 343 | + xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_PARITY ? '+' : '-', |
---|
| 344 | + xr_usb_serial->ctrlin & XR_USB_SERIAL_CTRL_OVERRUN ? '+' : '-');*/ |
---|
| 345 | + break; |
---|
| 346 | + |
---|
| 347 | + default: |
---|
| 348 | + dev_dbg(&xr_usb_serial->control->dev, |
---|
| 349 | + "%s - unknown notification %d received: index %d " |
---|
| 350 | + "len %d data0 %d data1 %d\n", |
---|
| 351 | + __func__, |
---|
| 352 | + dr->bNotificationType, dr->wIndex, |
---|
| 353 | + dr->wLength, data[0], data[1]); |
---|
| 354 | + break; |
---|
| 355 | + } |
---|
| 356 | +exit: |
---|
| 357 | + retval = usb_submit_urb(urb, GFP_ATOMIC); |
---|
| 358 | + if (retval) |
---|
| 359 | + dev_err(&xr_usb_serial->control->dev, "%s - usb_submit_urb failed: %d\n", |
---|
| 360 | + __func__, retval); |
---|
| 361 | +} |
---|
| 362 | + |
---|
| 363 | +static int xr_usb_serial_submit_read_urb(struct xr_usb_serial *xr_usb_serial, int index, gfp_t mem_flags) |
---|
| 364 | +{ |
---|
| 365 | + int res; |
---|
| 366 | + |
---|
| 367 | + if (!test_and_clear_bit(index, &xr_usb_serial->read_urbs_free)) |
---|
| 368 | + return 0; |
---|
| 369 | + |
---|
| 370 | + dev_vdbg(&xr_usb_serial->data->dev, "%s - urb %d\n", __func__, index); |
---|
| 371 | + |
---|
| 372 | + res = usb_submit_urb(xr_usb_serial->read_urbs[index], mem_flags); |
---|
| 373 | + if (res) { |
---|
| 374 | + if (res != -EPERM) { |
---|
| 375 | + dev_err(&xr_usb_serial->data->dev, |
---|
| 376 | + "%s - usb_submit_urb failed: %d\n", |
---|
| 377 | + __func__, res); |
---|
| 378 | + } |
---|
| 379 | + set_bit(index, &xr_usb_serial->read_urbs_free); |
---|
| 380 | + return res; |
---|
| 381 | + } |
---|
| 382 | + |
---|
| 383 | + return 0; |
---|
| 384 | +} |
---|
| 385 | + |
---|
| 386 | +static int xr_usb_serial_submit_read_urbs(struct xr_usb_serial *xr_usb_serial, gfp_t mem_flags) |
---|
| 387 | +{ |
---|
| 388 | + int res; |
---|
| 389 | + int i; |
---|
| 390 | + |
---|
| 391 | + for (i = 0; i < xr_usb_serial->rx_buflimit; ++i) { |
---|
| 392 | + res = xr_usb_serial_submit_read_urb(xr_usb_serial, i, mem_flags); |
---|
| 393 | + if (res) |
---|
| 394 | + return res; |
---|
| 395 | + } |
---|
| 396 | + |
---|
| 397 | + return 0; |
---|
| 398 | +} |
---|
| 399 | +static void xr_usb_serial_process_read_urb(struct xr_usb_serial *xr_usb_serial, struct urb *urb) |
---|
| 400 | +{ |
---|
| 401 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0) |
---|
| 402 | +#else |
---|
| 403 | + struct tty_struct *tty; |
---|
| 404 | +#endif |
---|
| 405 | + int preciseflags = xr_usb_serial->preciseflags; |
---|
| 406 | + int have_extra_byte; |
---|
| 407 | + int length; |
---|
| 408 | + |
---|
| 409 | + if (!urb->actual_length) |
---|
| 410 | + return; |
---|
| 411 | + |
---|
| 412 | + if (preciseflags) |
---|
| 413 | + { |
---|
| 414 | + char *dp = urb->transfer_buffer; |
---|
| 415 | + int i, ch, ch_flags; |
---|
| 416 | + |
---|
| 417 | + length = urb->actual_length; |
---|
| 418 | + length = length + (xr_usb_serial->have_extra_byte ? 1 : 0); |
---|
| 419 | + have_extra_byte = (preciseflags && (length & 1)); |
---|
| 420 | + length = (preciseflags) ? (length / 2) : length; |
---|
| 421 | + for (i = 0; i < length; ++i) |
---|
| 422 | + { |
---|
| 423 | + char tty_flag; |
---|
| 424 | + if (i == 0) |
---|
| 425 | + { |
---|
| 426 | + if (xr_usb_serial->have_extra_byte) |
---|
| 427 | + { |
---|
| 428 | + ch = xr_usb_serial->extra_byte; |
---|
| 429 | + } |
---|
| 430 | + else |
---|
| 431 | + { |
---|
| 432 | + ch = *dp++; |
---|
| 433 | + } |
---|
| 434 | + } |
---|
| 435 | + else |
---|
| 436 | + { |
---|
| 437 | + ch = *dp++; |
---|
| 438 | + } |
---|
| 439 | + ch_flags = *dp++; |
---|
| 440 | + if (ch_flags & RAMCTL_BUFFER_PARITY) |
---|
| 441 | + tty_flag = TTY_PARITY; |
---|
| 442 | + else if (ch_flags & RAMCTL_BUFFER_BREAK) |
---|
| 443 | + tty_flag = TTY_BREAK; |
---|
| 444 | + else if (ch_flags & RAMCTL_BUFFER_FRAME) |
---|
| 445 | + tty_flag = TTY_FRAME; |
---|
| 446 | + else if (ch_flags & RAMCTL_BUFFER_OVERRUN) |
---|
| 447 | + tty_flag = TTY_OVERRUN; |
---|
| 448 | + else |
---|
| 449 | + tty_flag = TTY_NORMAL; |
---|
| 450 | + |
---|
| 451 | + |
---|
| 452 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) |
---|
| 453 | + tty_insert_flip_char(&xr_usb_serial->port, ch, tty_flag); |
---|
| 454 | + tty_flip_buffer_push(&xr_usb_serial->port); |
---|
| 455 | +#else |
---|
| 456 | + tty = tty_port_tty_get(&xr_usb_serial->port); |
---|
| 457 | + if (!tty) |
---|
| 458 | + return; |
---|
| 459 | + tty_insert_flip_char(&xr_usb_serial->port, ch, tty_flag); |
---|
| 460 | + tty_flip_buffer_push(tty); |
---|
| 461 | + |
---|
| 462 | + tty_kref_put(tty); |
---|
| 463 | +#endif |
---|
| 464 | + |
---|
| 465 | + } |
---|
| 466 | + } |
---|
| 467 | + else |
---|
| 468 | + { |
---|
| 469 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) |
---|
| 470 | + tty_insert_flip_string(&xr_usb_serial->port, urb->transfer_buffer, |
---|
| 471 | + urb->actual_length); |
---|
| 472 | + tty_flip_buffer_push(&xr_usb_serial->port); |
---|
| 473 | +#else |
---|
| 474 | + tty = tty_port_tty_get(&xr_usb_serial->port); |
---|
| 475 | + if (!tty) |
---|
| 476 | + return; |
---|
| 477 | + tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length); |
---|
| 478 | + tty_flip_buffer_push(tty); |
---|
| 479 | + |
---|
| 480 | + tty_kref_put(tty); |
---|
| 481 | +#endif |
---|
| 482 | + } |
---|
| 483 | +} |
---|
| 484 | + |
---|
| 485 | +static void xr_usb_serial_read_bulk_callback(struct urb *urb) |
---|
| 486 | +{ |
---|
| 487 | + struct xr_usb_serial_rb *rb = urb->context; |
---|
| 488 | + struct xr_usb_serial *xr_usb_serial = rb->instance; |
---|
| 489 | + unsigned long flags; |
---|
| 490 | + |
---|
| 491 | + dev_vdbg(&xr_usb_serial->data->dev, "%s - urb %d, len %d\n", __func__, |
---|
| 492 | + rb->index, urb->actual_length); |
---|
| 493 | + set_bit(rb->index, &xr_usb_serial->read_urbs_free); |
---|
| 494 | + |
---|
| 495 | + if (!xr_usb_serial->dev) { |
---|
| 496 | + dev_dbg(&xr_usb_serial->data->dev, "%s - disconnected\n", __func__); |
---|
| 497 | + return; |
---|
| 498 | + } |
---|
| 499 | + usb_mark_last_busy(xr_usb_serial->dev); |
---|
| 500 | + |
---|
| 501 | + if (urb->status) { |
---|
| 502 | + /* by fuyingzhe 2021.01.08 |
---|
| 503 | + dev_dbg(&xr_usb_serial->data->dev, "%s - non-zero urb status: %d\n", |
---|
| 504 | + __func__, urb->status); |
---|
| 505 | + */ |
---|
| 506 | + //return; |
---|
| 507 | + } |
---|
| 508 | + xr_usb_serial_process_read_urb(xr_usb_serial, urb); |
---|
| 509 | + |
---|
| 510 | + /* throttle device if requested by tty */ |
---|
| 511 | + spin_lock_irqsave(&xr_usb_serial->read_lock, flags); |
---|
| 512 | + xr_usb_serial->throttled = xr_usb_serial->throttle_req; |
---|
| 513 | + if (!xr_usb_serial->throttled && !xr_usb_serial->susp_count) { |
---|
| 514 | + spin_unlock_irqrestore(&xr_usb_serial->read_lock, flags); |
---|
| 515 | + xr_usb_serial_submit_read_urb(xr_usb_serial, rb->index, GFP_ATOMIC); |
---|
| 516 | + } else { |
---|
| 517 | + spin_unlock_irqrestore(&xr_usb_serial->read_lock, flags); |
---|
| 518 | + } |
---|
| 519 | +} |
---|
| 520 | + |
---|
| 521 | +/* data interface wrote those outgoing bytes */ |
---|
| 522 | +static void xr_usb_serial_write_bulk(struct urb *urb) |
---|
| 523 | +{ |
---|
| 524 | + struct xr_usb_serial_wb *wb = urb->context; |
---|
| 525 | + struct xr_usb_serial *xr_usb_serial = wb->instance; |
---|
| 526 | + unsigned long flags; |
---|
| 527 | + |
---|
| 528 | + if (urb->status || (urb->actual_length != urb->transfer_buffer_length)) |
---|
| 529 | + dev_vdbg(&xr_usb_serial->data->dev, "%s - len %d/%d, status %d\n", |
---|
| 530 | + __func__, |
---|
| 531 | + urb->actual_length, |
---|
| 532 | + urb->transfer_buffer_length, |
---|
| 533 | + urb->status); |
---|
| 534 | + |
---|
| 535 | + spin_lock_irqsave(&xr_usb_serial->write_lock, flags); |
---|
| 536 | + xr_usb_serial_write_done(xr_usb_serial, wb); |
---|
| 537 | + spin_unlock_irqrestore(&xr_usb_serial->write_lock, flags); |
---|
| 538 | + schedule_work(&xr_usb_serial->work); |
---|
| 539 | +} |
---|
| 540 | + |
---|
| 541 | +static void xr_usb_serial_softint(struct work_struct *work) |
---|
| 542 | +{ |
---|
| 543 | + struct xr_usb_serial *xr_usb_serial = container_of(work, struct xr_usb_serial, work); |
---|
| 544 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0) |
---|
| 545 | +#else |
---|
| 546 | + struct tty_struct *tty; |
---|
| 547 | +#endif |
---|
| 548 | + |
---|
| 549 | + |
---|
| 550 | + dev_vdbg(&xr_usb_serial->data->dev, "%s\n", __func__); |
---|
| 551 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0) |
---|
| 552 | + tty_port_tty_wakeup(&xr_usb_serial->port); |
---|
| 553 | +#else |
---|
| 554 | + tty = tty_port_tty_get(&xr_usb_serial->port); |
---|
| 555 | + if (!tty) |
---|
| 556 | + return; |
---|
| 557 | + tty_wakeup(tty); |
---|
| 558 | + tty_kref_put(tty); |
---|
| 559 | +#endif |
---|
| 560 | +} |
---|
| 561 | + |
---|
| 562 | +/* |
---|
| 563 | + * TTY handlers |
---|
| 564 | + */ |
---|
| 565 | + |
---|
| 566 | +static int xr_usb_serial_tty_install(struct tty_driver *driver, struct tty_struct *tty) |
---|
| 567 | +{ |
---|
| 568 | + struct xr_usb_serial *xr_usb_serial; |
---|
| 569 | + int retval; |
---|
| 570 | + |
---|
| 571 | + //dev_dbg(tty->dev, "%s\n", __func__); |
---|
| 572 | + |
---|
| 573 | + xr_usb_serial = xr_usb_serial_get_by_index(tty->index); |
---|
| 574 | + if (!xr_usb_serial) |
---|
| 575 | + return -ENODEV; |
---|
| 576 | + |
---|
| 577 | + retval = tty_standard_install(driver, tty); |
---|
| 578 | + if (retval) |
---|
| 579 | + goto error_init_termios; |
---|
| 580 | + |
---|
| 581 | + tty->driver_data = xr_usb_serial; |
---|
| 582 | + |
---|
| 583 | + return 0; |
---|
| 584 | + |
---|
| 585 | +error_init_termios: |
---|
| 586 | + tty_port_put(&xr_usb_serial->port); |
---|
| 587 | + return retval; |
---|
| 588 | +} |
---|
| 589 | + |
---|
| 590 | +static int xr_usb_serial_tty_open(struct tty_struct *tty, struct file *filp) |
---|
| 591 | +{ |
---|
| 592 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 593 | + int result; |
---|
| 594 | + struct ktermios *s_termios = &tty->termios; |
---|
| 595 | + |
---|
| 596 | + result = xr_usb_serial_fifo_reset(xr_usb_serial); |
---|
| 597 | + //dev_dbg(tty->dev, "%s\n", __func__); |
---|
| 598 | + |
---|
| 599 | + /*Add by Fuyingzhe 2020.11.06*/ |
---|
| 600 | + /*Fix echo garbled*/ |
---|
| 601 | + s_termios->c_iflag = 0; |
---|
| 602 | + s_termios->c_oflag = 4; |
---|
| 603 | + s_termios->c_lflag = 35360; |
---|
| 604 | + xr_usb_serial_tty_set_termios(tty, s_termios); |
---|
| 605 | + /*Add END*/ |
---|
| 606 | + |
---|
| 607 | + return tty_port_open(&xr_usb_serial->port, tty, filp); |
---|
| 608 | +} |
---|
| 609 | + |
---|
| 610 | +static int xr_usb_serial_port_activate(struct tty_port *port, struct tty_struct *tty) |
---|
| 611 | +{ |
---|
| 612 | + struct xr_usb_serial *xr_usb_serial = container_of(port, struct xr_usb_serial, port); |
---|
| 613 | + int retval = -ENODEV; |
---|
| 614 | + |
---|
| 615 | + //dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__); |
---|
| 616 | + |
---|
| 617 | + mutex_lock(&xr_usb_serial->mutex); |
---|
| 618 | + if (xr_usb_serial->disconnected) |
---|
| 619 | + goto disconnected; |
---|
| 620 | + |
---|
| 621 | + retval = usb_autopm_get_interface(xr_usb_serial->control); |
---|
| 622 | + if (retval) |
---|
| 623 | + goto error_get_interface; |
---|
| 624 | + |
---|
| 625 | + /* |
---|
| 626 | + * FIXME: Why do we need this? Allocating 64K of physically contiguous |
---|
| 627 | + * memory is really nasty... |
---|
| 628 | + */ |
---|
| 629 | + set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); |
---|
| 630 | + xr_usb_serial->control->needs_remote_wakeup = 1; |
---|
| 631 | + |
---|
| 632 | + xr_usb_serial->ctrlurb->dev = xr_usb_serial->dev; |
---|
| 633 | + if (usb_submit_urb(xr_usb_serial->ctrlurb, GFP_KERNEL)) { |
---|
| 634 | + dev_err(&xr_usb_serial->control->dev, |
---|
| 635 | + "%s - usb_submit_urb(ctrl irq) failed\n", __func__); |
---|
| 636 | + goto error_submit_urb; |
---|
| 637 | + } |
---|
| 638 | + |
---|
| 639 | + xr_usb_serial->ctrlout = XR_USB_SERIAL_CTRL_DTR | XR_USB_SERIAL_CTRL_RTS; |
---|
| 640 | + if (xr_usb_serial_set_control(xr_usb_serial, xr_usb_serial->ctrlout) < 0 && |
---|
| 641 | + (xr_usb_serial->ctrl_caps & USB_CDC_CAP_LINE)) |
---|
| 642 | + goto error_set_control; |
---|
| 643 | + |
---|
| 644 | + usb_autopm_put_interface(xr_usb_serial->control); |
---|
| 645 | + |
---|
| 646 | + /* |
---|
| 647 | + * Unthrottle device in case the TTY was closed while throttled. |
---|
| 648 | + */ |
---|
| 649 | + spin_lock_irq(&xr_usb_serial->read_lock); |
---|
| 650 | + xr_usb_serial->throttled = 0; |
---|
| 651 | + xr_usb_serial->throttle_req = 0; |
---|
| 652 | + spin_unlock_irq(&xr_usb_serial->read_lock); |
---|
| 653 | + |
---|
| 654 | + if (xr_usb_serial_submit_read_urbs(xr_usb_serial, GFP_KERNEL)) |
---|
| 655 | + goto error_submit_read_urbs; |
---|
| 656 | + |
---|
| 657 | + mutex_unlock(&xr_usb_serial->mutex); |
---|
| 658 | + |
---|
| 659 | + return 0; |
---|
| 660 | + |
---|
| 661 | +error_submit_read_urbs: |
---|
| 662 | + xr_usb_serial->ctrlout = 0; |
---|
| 663 | + xr_usb_serial_set_control(xr_usb_serial, xr_usb_serial->ctrlout); |
---|
| 664 | +error_set_control: |
---|
| 665 | + usb_kill_urb(xr_usb_serial->ctrlurb); |
---|
| 666 | +error_submit_urb: |
---|
| 667 | + usb_autopm_put_interface(xr_usb_serial->control); |
---|
| 668 | +error_get_interface: |
---|
| 669 | +disconnected: |
---|
| 670 | + mutex_unlock(&xr_usb_serial->mutex); |
---|
| 671 | + return retval; |
---|
| 672 | +} |
---|
| 673 | + |
---|
| 674 | +static void xr_usb_serial_port_destruct(struct tty_port *port) |
---|
| 675 | +{ |
---|
| 676 | + struct xr_usb_serial *xr_usb_serial = container_of(port, struct xr_usb_serial, port); |
---|
| 677 | + |
---|
| 678 | + dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__); |
---|
| 679 | + #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) |
---|
| 680 | + tty_unregister_device(xr_usb_serial_tty_driver, xr_usb_serial->minor); |
---|
| 681 | + #endif |
---|
| 682 | + xr_usb_serial_release_minor(xr_usb_serial); |
---|
| 683 | + usb_put_intf(xr_usb_serial->control); |
---|
| 684 | + kfree(xr_usb_serial->country_codes); |
---|
| 685 | + kfree(xr_usb_serial); |
---|
| 686 | +} |
---|
| 687 | + |
---|
| 688 | +static void xr_usb_serial_port_shutdown(struct tty_port *port) |
---|
| 689 | +{ |
---|
| 690 | + struct xr_usb_serial *xr_usb_serial = container_of(port, struct xr_usb_serial, port); |
---|
| 691 | + int i; |
---|
| 692 | + |
---|
| 693 | + //dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__); |
---|
| 694 | + |
---|
| 695 | + mutex_lock(&xr_usb_serial->mutex); |
---|
| 696 | + printk(KERN_ERR"************** in xr_usb_serial_port_shutdown, mdelay 5000\n"); |
---|
| 697 | + mdelay(5000); |
---|
| 698 | + if (!xr_usb_serial->disconnected) { |
---|
| 699 | + usb_autopm_get_interface(xr_usb_serial->control); |
---|
| 700 | + xr_usb_serial_set_control(xr_usb_serial, xr_usb_serial->ctrlout = 0); |
---|
| 701 | + usb_kill_urb(xr_usb_serial->ctrlurb); |
---|
| 702 | + for (i = 0; i < XR_USB_SERIAL_NW; i++) |
---|
| 703 | + usb_kill_urb(xr_usb_serial->wb[i].urb); |
---|
| 704 | + for (i = 0; i < xr_usb_serial->rx_buflimit; i++) |
---|
| 705 | + usb_kill_urb(xr_usb_serial->read_urbs[i]); |
---|
| 706 | + xr_usb_serial->control->needs_remote_wakeup = 0; |
---|
| 707 | + usb_autopm_put_interface(xr_usb_serial->control); |
---|
| 708 | + } |
---|
| 709 | + |
---|
| 710 | + mutex_unlock(&xr_usb_serial->mutex); |
---|
| 711 | + printk(KERN_ERR"************** end xr_usb_serial_port_shutdown, mdelay 5000\n"); |
---|
| 712 | + mdelay(5000); |
---|
| 713 | +} |
---|
| 714 | + |
---|
| 715 | +static void xr_usb_serial_tty_cleanup(struct tty_struct *tty) |
---|
| 716 | +{ |
---|
| 717 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 718 | + //dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__); |
---|
| 719 | + tty_port_put(&xr_usb_serial->port); |
---|
| 720 | +} |
---|
| 721 | + |
---|
| 722 | +static void xr_usb_serial_tty_hangup(struct tty_struct *tty) |
---|
| 723 | +{ |
---|
| 724 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 725 | + dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__); |
---|
| 726 | + tty_port_hangup(&xr_usb_serial->port); |
---|
| 727 | +} |
---|
| 728 | + |
---|
| 729 | +static void xr_usb_serial_tty_close(struct tty_struct *tty, struct file *filp) |
---|
| 730 | +{ |
---|
| 731 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 732 | + //dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__); |
---|
| 733 | + tty_port_close(&xr_usb_serial->port, tty, filp); |
---|
| 734 | +} |
---|
| 735 | + |
---|
| 736 | +static int xr_usb_serial_tty_write(struct tty_struct *tty, |
---|
| 737 | + const unsigned char *buf, int count) |
---|
| 738 | +{ |
---|
| 739 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 740 | + int stat; |
---|
| 741 | + unsigned long flags; |
---|
| 742 | + int wbn; |
---|
| 743 | + struct xr_usb_serial_wb *wb; |
---|
| 744 | + |
---|
| 745 | + if (!count) |
---|
| 746 | + return 0; |
---|
| 747 | + |
---|
| 748 | + //dev_vdbg(&xr_usb_serial->data->dev, "%s - count %d\n", __func__, count); |
---|
| 749 | + |
---|
| 750 | + spin_lock_irqsave(&xr_usb_serial->write_lock, flags); |
---|
| 751 | + wbn = xr_usb_serial_wb_alloc(xr_usb_serial); |
---|
| 752 | + if (wbn < 0) { |
---|
| 753 | + spin_unlock_irqrestore(&xr_usb_serial->write_lock, flags); |
---|
| 754 | + return 0; |
---|
| 755 | + } |
---|
| 756 | + wb = &xr_usb_serial->wb[wbn]; |
---|
| 757 | + |
---|
| 758 | + if (!xr_usb_serial->dev) { |
---|
| 759 | + wb->use = 0; |
---|
| 760 | + spin_unlock_irqrestore(&xr_usb_serial->write_lock, flags); |
---|
| 761 | + return -ENODEV; |
---|
| 762 | + } |
---|
| 763 | + |
---|
| 764 | + count = (count > xr_usb_serial->writesize) ? xr_usb_serial->writesize : count; |
---|
| 765 | + //dev_vdbg(&xr_usb_serial->data->dev, "%s - write %d\n", __func__, count); |
---|
| 766 | + memcpy(wb->buf, buf, count); |
---|
| 767 | + wb->len = count; |
---|
| 768 | + |
---|
| 769 | + usb_autopm_get_interface_async(xr_usb_serial->control); |
---|
| 770 | + if (xr_usb_serial->susp_count) { |
---|
| 771 | + if (!xr_usb_serial->delayed_wb) |
---|
| 772 | + xr_usb_serial->delayed_wb = wb; |
---|
| 773 | + else |
---|
| 774 | + usb_autopm_put_interface_async(xr_usb_serial->control); |
---|
| 775 | + spin_unlock_irqrestore(&xr_usb_serial->write_lock, flags); |
---|
| 776 | + return count; /* A white lie */ |
---|
| 777 | + } |
---|
| 778 | + usb_mark_last_busy(xr_usb_serial->dev); |
---|
| 779 | + |
---|
| 780 | + stat = xr_usb_serial_start_wb(xr_usb_serial, wb); |
---|
| 781 | + spin_unlock_irqrestore(&xr_usb_serial->write_lock, flags); |
---|
| 782 | + |
---|
| 783 | + if (stat < 0) |
---|
| 784 | + return stat; |
---|
| 785 | + return count; |
---|
| 786 | +} |
---|
| 787 | + |
---|
| 788 | +static int xr_usb_serial_tty_write_room(struct tty_struct *tty) |
---|
| 789 | +{ |
---|
| 790 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 791 | + /* |
---|
| 792 | + * Do not let the line discipline to know that we have a reserve, |
---|
| 793 | + * or it might get too enthusiastic. |
---|
| 794 | + */ |
---|
| 795 | + return xr_usb_serial_wb_is_avail(xr_usb_serial) ? xr_usb_serial->writesize : 0; |
---|
| 796 | +} |
---|
| 797 | + |
---|
| 798 | +static int xr_usb_serial_tty_chars_in_buffer(struct tty_struct *tty) |
---|
| 799 | +{ |
---|
| 800 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 801 | + /* |
---|
| 802 | + * if the device was unplugged then any remaining characters fell out |
---|
| 803 | + * of the connector ;) |
---|
| 804 | + */ |
---|
| 805 | + if (xr_usb_serial->disconnected) |
---|
| 806 | + return 0; |
---|
| 807 | + /* |
---|
| 808 | + * This is inaccurate (overcounts), but it works. |
---|
| 809 | + */ |
---|
| 810 | + return (XR_USB_SERIAL_NW - xr_usb_serial_wb_is_avail(xr_usb_serial)) * xr_usb_serial->writesize; |
---|
| 811 | +} |
---|
| 812 | + |
---|
| 813 | +static void xr_usb_serial_tty_throttle(struct tty_struct *tty) |
---|
| 814 | +{ |
---|
| 815 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 816 | + |
---|
| 817 | + spin_lock_irq(&xr_usb_serial->read_lock); |
---|
| 818 | + xr_usb_serial->throttle_req = 1; |
---|
| 819 | + spin_unlock_irq(&xr_usb_serial->read_lock); |
---|
| 820 | +} |
---|
| 821 | + |
---|
| 822 | +static void xr_usb_serial_tty_unthrottle(struct tty_struct *tty) |
---|
| 823 | +{ |
---|
| 824 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 825 | + unsigned int was_throttled; |
---|
| 826 | + |
---|
| 827 | + spin_lock_irq(&xr_usb_serial->read_lock); |
---|
| 828 | + was_throttled = xr_usb_serial->throttled; |
---|
| 829 | + xr_usb_serial->throttled = 0; |
---|
| 830 | + xr_usb_serial->throttle_req = 0; |
---|
| 831 | + spin_unlock_irq(&xr_usb_serial->read_lock); |
---|
| 832 | + |
---|
| 833 | + if (was_throttled) |
---|
| 834 | + xr_usb_serial_submit_read_urbs(xr_usb_serial, GFP_KERNEL); |
---|
| 835 | +} |
---|
| 836 | + |
---|
| 837 | +static int xr_usb_serial_tty_break_ctl(struct tty_struct *tty, int state) |
---|
| 838 | +{ |
---|
| 839 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 840 | + int retval; |
---|
| 841 | + |
---|
| 842 | + retval = xr_usb_serial_send_break(xr_usb_serial, state ? 0xffff : 0); |
---|
| 843 | + if (retval < 0) |
---|
| 844 | + dev_err(&xr_usb_serial->control->dev, "%s - send break failed\n", |
---|
| 845 | + __func__); |
---|
| 846 | + return retval; |
---|
| 847 | +} |
---|
| 848 | + |
---|
| 849 | +static int xr_usb_serial_tty_tiocmget(struct tty_struct *tty) |
---|
| 850 | +{ |
---|
| 851 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 852 | + //dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tty_tiocmget\n"); |
---|
| 853 | + return xr_usb_serial_tiocmget(xr_usb_serial); |
---|
| 854 | + |
---|
| 855 | +} |
---|
| 856 | + |
---|
| 857 | +static int xr_usb_serial_tty_tiocmset(struct tty_struct *tty, |
---|
| 858 | + unsigned int set, unsigned int clear) |
---|
| 859 | +{ |
---|
| 860 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 861 | + //dev_dbg(&xr_usb_serial->control->dev, "xr_usb_serial_tty_tiocmset set=0x%x clear=0x%x\n",set,clear); |
---|
| 862 | + return xr_usb_serial_tiocmset(xr_usb_serial,set,clear); |
---|
| 863 | + |
---|
| 864 | +} |
---|
| 865 | + |
---|
| 866 | +static int get_serial_info(struct xr_usb_serial *xr_usb_serial, struct serial_struct __user *info) |
---|
| 867 | +{ |
---|
| 868 | + struct serial_struct tmp; |
---|
| 869 | + |
---|
| 870 | + if (!info) |
---|
| 871 | + return -EINVAL; |
---|
| 872 | + |
---|
| 873 | + memset(&tmp, 0, sizeof(tmp)); |
---|
| 874 | + tmp.flags = ASYNC_LOW_LATENCY; |
---|
| 875 | + tmp.xmit_fifo_size = xr_usb_serial->writesize; |
---|
| 876 | + tmp.baud_base = le32_to_cpu(xr_usb_serial->line.dwDTERate); |
---|
| 877 | + tmp.close_delay = xr_usb_serial->port.close_delay / 10; |
---|
| 878 | + tmp.closing_wait = xr_usb_serial->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? |
---|
| 879 | + ASYNC_CLOSING_WAIT_NONE : |
---|
| 880 | + xr_usb_serial->port.closing_wait / 10; |
---|
| 881 | + |
---|
| 882 | + if (copy_to_user(info, &tmp, sizeof(tmp))) |
---|
| 883 | + return -EFAULT; |
---|
| 884 | + else |
---|
| 885 | + return 0; |
---|
| 886 | +} |
---|
| 887 | + |
---|
| 888 | +static int set_serial_info(struct xr_usb_serial *xr_usb_serial, |
---|
| 889 | + struct serial_struct __user *newinfo) |
---|
| 890 | +{ |
---|
| 891 | + struct serial_struct new_serial; |
---|
| 892 | + unsigned int closing_wait, close_delay; |
---|
| 893 | + int retval = 0; |
---|
| 894 | + |
---|
| 895 | + if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) |
---|
| 896 | + return -EFAULT; |
---|
| 897 | + |
---|
| 898 | + close_delay = new_serial.close_delay * 10; |
---|
| 899 | + closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? |
---|
| 900 | + ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; |
---|
| 901 | + |
---|
| 902 | + mutex_lock(&xr_usb_serial->port.mutex); |
---|
| 903 | + |
---|
| 904 | + if (!capable(CAP_SYS_ADMIN)) { |
---|
| 905 | + if ((close_delay != xr_usb_serial->port.close_delay) || |
---|
| 906 | + (closing_wait != xr_usb_serial->port.closing_wait)) |
---|
| 907 | + retval = -EPERM; |
---|
| 908 | + else |
---|
| 909 | + retval = -EOPNOTSUPP; |
---|
| 910 | + } else { |
---|
| 911 | + xr_usb_serial->port.close_delay = close_delay; |
---|
| 912 | + xr_usb_serial->port.closing_wait = closing_wait; |
---|
| 913 | + } |
---|
| 914 | + |
---|
| 915 | + mutex_unlock(&xr_usb_serial->port.mutex); |
---|
| 916 | + return retval; |
---|
| 917 | +} |
---|
| 918 | + |
---|
| 919 | +static int xr_usb_serial_tty_ioctl(struct tty_struct *tty, |
---|
| 920 | + unsigned int cmd, unsigned long arg) |
---|
| 921 | +{ |
---|
| 922 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 923 | + int rv = -ENOIOCTLCMD; |
---|
| 924 | + unsigned int channel,reg, val,preciseflags; |
---|
| 925 | + int baud_rate = 0; |
---|
| 926 | + struct usb_cdc_line_coding newline; |
---|
| 927 | + short *data; |
---|
| 928 | + switch (cmd) { |
---|
| 929 | + case TIOCGSERIAL: /* gets serial port data */ |
---|
| 930 | + rv = get_serial_info(xr_usb_serial, (struct serial_struct __user *) arg); |
---|
| 931 | + break; |
---|
| 932 | + case TIOCSSERIAL: |
---|
| 933 | + rv = set_serial_info(xr_usb_serial, (struct serial_struct __user *) arg); |
---|
| 934 | + break; |
---|
| 935 | + case XR_USB_SERIAL_GET_REG: |
---|
| 936 | + if (get_user(channel, (int __user *)arg)) |
---|
| 937 | + return -EFAULT; |
---|
| 938 | + if (get_user(reg, (int __user *)(arg + sizeof(int)))) |
---|
| 939 | + return -EFAULT; |
---|
| 940 | + |
---|
| 941 | + data = kmalloc(2, GFP_KERNEL); |
---|
| 942 | + if (data == NULL) { |
---|
| 943 | + dev_err(&xr_usb_serial->control->dev, "%s - Cannot allocate USB buffer.\n", __func__); |
---|
| 944 | + return -ENOMEM; |
---|
| 945 | + } |
---|
| 946 | + |
---|
| 947 | + if (channel == -1) |
---|
| 948 | + { |
---|
| 949 | + rv = xr_usb_serial_get_reg(xr_usb_serial,reg, data); |
---|
| 950 | + } |
---|
| 951 | + else |
---|
| 952 | + { |
---|
| 953 | + rv = xr_usb_serial_get_reg_ext(xr_usb_serial,channel,reg, data); |
---|
| 954 | + } |
---|
| 955 | + if (rv < 0) |
---|
| 956 | + { |
---|
| 957 | + dev_err(&xr_usb_serial->control->dev, "Cannot get register (%d)\n", rv); |
---|
| 958 | + kfree(data); |
---|
| 959 | + return -EFAULT; |
---|
| 960 | + } |
---|
| 961 | + if (put_user(le16_to_cpu(*data), (int __user *)(arg + 2 * sizeof(int)))) |
---|
| 962 | + { |
---|
| 963 | + dev_err(&xr_usb_serial->control->dev, "Cannot put user result\n"); |
---|
| 964 | + kfree(data); |
---|
| 965 | + return -EFAULT; |
---|
| 966 | + } |
---|
| 967 | + rv = 0; |
---|
| 968 | + kfree(data); |
---|
| 969 | + break; |
---|
| 970 | + |
---|
| 971 | + case XR_USB_SERIAL_SET_REG: |
---|
| 972 | + if (get_user(channel, (int __user *)arg)) |
---|
| 973 | + return -EFAULT; |
---|
| 974 | + if (get_user(reg, (int __user *)(arg + sizeof(int)))) |
---|
| 975 | + return -EFAULT; |
---|
| 976 | + if (get_user(val, (int __user *)(arg + 2 * sizeof(int)))) |
---|
| 977 | + return -EFAULT; |
---|
| 978 | + |
---|
| 979 | + if (channel == -1) |
---|
| 980 | + { |
---|
| 981 | + rv = xr_usb_serial_set_reg(xr_usb_serial,reg, val); |
---|
| 982 | + } |
---|
| 983 | + else |
---|
| 984 | + { |
---|
| 985 | + rv = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,reg, val); |
---|
| 986 | + |
---|
| 987 | + } |
---|
| 988 | + if (rv < 0) |
---|
| 989 | + return -EFAULT; |
---|
| 990 | + rv = 0; |
---|
| 991 | + break; |
---|
| 992 | + case XR_USB_SERIAL_LOOPBACK: |
---|
| 993 | + if (get_user(channel, (int __user *)arg)) |
---|
| 994 | + return -EFAULT; |
---|
| 995 | + if (channel == -1) |
---|
| 996 | + channel = xr_usb_serial->channel; |
---|
| 997 | + rv = xr_usb_serial_set_loopback(xr_usb_serial,channel); |
---|
| 998 | + if (rv < 0) |
---|
| 999 | + return -EFAULT; |
---|
| 1000 | + rv = 0; |
---|
| 1001 | + break; |
---|
| 1002 | + case XR_USB_SERIAL_SET_GPIO_MODE_REG: |
---|
| 1003 | + xr_usb_serial_disable(xr_usb_serial); |
---|
| 1004 | + if (get_user(channel, (int __user *)arg)) |
---|
| 1005 | + return -EFAULT; |
---|
| 1006 | + if (get_user(val, (int __user *)(arg + sizeof(int)))) |
---|
| 1007 | + return -EFAULT; |
---|
| 1008 | + if (channel == -1) |
---|
| 1009 | + { |
---|
| 1010 | + //block = portdata->block; |
---|
| 1011 | + rv = xr_usb_serial_set_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_gpio_mode_addr, val); |
---|
| 1012 | + } |
---|
| 1013 | + else |
---|
| 1014 | + { |
---|
| 1015 | + rv = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,xr_usb_serial->reg_map.uart_gpio_mode_addr, val); |
---|
| 1016 | + } |
---|
| 1017 | + |
---|
| 1018 | + dev_dbg(&xr_usb_serial->control->dev, "XR_USB_SERIAL_SET_GPIO_MODE_REG 0x%x val:0x%x \n", xr_usb_serial->reg_map.uart_gpio_mode_addr,val); |
---|
| 1019 | + xr_usb_serial_enable(xr_usb_serial); |
---|
| 1020 | + if (rv < 0) |
---|
| 1021 | + return -EFAULT; |
---|
| 1022 | + break; |
---|
| 1023 | + case XR_USB_SERIAL_GET_GPIO_MODE_REG: |
---|
| 1024 | + xr_usb_serial_disable(xr_usb_serial); |
---|
| 1025 | + if (get_user(channel, (int __user *)arg)) |
---|
| 1026 | + return -EFAULT; |
---|
| 1027 | + |
---|
| 1028 | + data = kmalloc(2, GFP_KERNEL); |
---|
| 1029 | + if (data == NULL) { |
---|
| 1030 | + dev_err(&xr_usb_serial->control->dev, "%s - Cannot allocate USB buffer.\n", __func__); |
---|
| 1031 | + return -ENOMEM; |
---|
| 1032 | + } |
---|
| 1033 | + |
---|
| 1034 | + if (channel == -1) |
---|
| 1035 | + { |
---|
| 1036 | + rv = xr_usb_serial_get_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_gpio_mode_addr, data); |
---|
| 1037 | + } |
---|
| 1038 | + else |
---|
| 1039 | + { |
---|
| 1040 | + rv = xr_usb_serial_get_reg_ext(xr_usb_serial,channel,xr_usb_serial->reg_map.uart_gpio_mode_addr,data); |
---|
| 1041 | + } |
---|
| 1042 | + |
---|
| 1043 | + xr_usb_serial_enable(xr_usb_serial); |
---|
| 1044 | + |
---|
| 1045 | + dev_dbg(&xr_usb_serial->control->dev, "XR_USB_SERIAL_GET_GPIO_MODE_REG 0x%x val:0x%x \n", xr_usb_serial->reg_map.uart_gpio_mode_addr,*data); |
---|
| 1046 | + |
---|
| 1047 | + if (rv < 0 ) { |
---|
| 1048 | + dev_err(&xr_usb_serial->control->dev, "Cannot get register (%d) channel=%d \n", rv,channel); |
---|
| 1049 | + kfree(data); |
---|
| 1050 | + return -EFAULT; |
---|
| 1051 | + } |
---|
| 1052 | + |
---|
| 1053 | + if (put_user(data[0], (int __user *)(arg + sizeof(int)))) { |
---|
| 1054 | + dev_err(&xr_usb_serial->control->dev, "Cannot put user result\n"); |
---|
| 1055 | + kfree(data); |
---|
| 1056 | + return -EFAULT; |
---|
| 1057 | + } |
---|
| 1058 | + |
---|
| 1059 | + kfree(data); |
---|
| 1060 | + break; |
---|
| 1061 | + case XRIOC_SET_ANY_BAUD_RATE: |
---|
| 1062 | + |
---|
| 1063 | + if (get_user(baud_rate, (int __user *)arg)) { |
---|
| 1064 | + dev_dbg(&xr_usb_serial->control->dev, "get_user errot \n"); |
---|
| 1065 | + return -EFAULT; |
---|
| 1066 | + } |
---|
| 1067 | + xr_usb_serial->line.dwDTERate = baud_rate; |
---|
| 1068 | + memcpy(&newline,&(xr_usb_serial->line),sizeof(struct usb_cdc_line_coding)); |
---|
| 1069 | + xr_usb_serial_disable(xr_usb_serial); |
---|
| 1070 | + rv = xr_usb_serial_set_line(xr_usb_serial,&newline); |
---|
| 1071 | + xr_usb_serial_enable(xr_usb_serial); |
---|
| 1072 | + dev_dbg(&xr_usb_serial->control->dev, "XRIOC_SET_ANY_BAUD_RATE set baud_rate:%d ret=%d\n", baud_rate,rv); |
---|
| 1073 | + break; |
---|
| 1074 | + case XRIOC_SET_PRECISE_FLAGS: |
---|
| 1075 | + preciseflags = arg; |
---|
| 1076 | + dev_dbg(&xr_usb_serial->control->dev, "%s VIOC_SET_PRECISE_FLAGS %d\n", __func__, preciseflags); |
---|
| 1077 | + xr_usb_serial_disable(xr_usb_serial); |
---|
| 1078 | + if (preciseflags) |
---|
| 1079 | + { |
---|
| 1080 | + xr_usb_serial->preciseflags = 1; |
---|
| 1081 | + } |
---|
| 1082 | + else |
---|
| 1083 | + { |
---|
| 1084 | + xr_usb_serial->preciseflags = 0; |
---|
| 1085 | + } |
---|
| 1086 | + xr_usb_serial_set_wide_mode(xr_usb_serial,xr_usb_serial->preciseflags); |
---|
| 1087 | + xr_usb_serial_enable(xr_usb_serial); |
---|
| 1088 | + break; |
---|
| 1089 | + } |
---|
| 1090 | + |
---|
| 1091 | + return rv; |
---|
| 1092 | +} |
---|
| 1093 | + |
---|
| 1094 | +static void xr_usb_serial_tty_set_termios(struct tty_struct *tty, |
---|
| 1095 | + struct ktermios *termios_old) |
---|
| 1096 | +{ |
---|
| 1097 | + struct xr_usb_serial *xr_usb_serial = tty->driver_data; |
---|
| 1098 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) |
---|
| 1099 | + struct ktermios *termios = tty->termios; |
---|
| 1100 | +#else |
---|
| 1101 | + struct ktermios *termios = &tty->termios; |
---|
| 1102 | +#endif |
---|
| 1103 | + unsigned int cflag = termios->c_cflag; |
---|
| 1104 | + struct usb_cdc_line_coding newline; |
---|
| 1105 | + int newctrl = xr_usb_serial->ctrlout; |
---|
| 1106 | + xr_usb_serial_disable(xr_usb_serial); |
---|
| 1107 | + newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); |
---|
| 1108 | + newline.bCharFormat = termios->c_cflag & CSTOPB ? 1 : 0; |
---|
| 1109 | + newline.bParityType = termios->c_cflag & PARENB ? |
---|
| 1110 | + (termios->c_cflag & PARODD ? 1 : 2) + |
---|
| 1111 | + (termios->c_cflag & CMSPAR ? 2 : 0) : 0; |
---|
| 1112 | + xr_usb_serial->trans9 = 0; |
---|
| 1113 | + switch (termios->c_cflag & CSIZE) { |
---|
| 1114 | + case CS5:/*using CS5 replace of the 9 bit data mode*/ |
---|
| 1115 | + newline.bDataBits = 9; |
---|
| 1116 | + xr_usb_serial->trans9 =1; |
---|
| 1117 | + break; |
---|
| 1118 | + case CS6: |
---|
| 1119 | + newline.bDataBits = 6; |
---|
| 1120 | + break; |
---|
| 1121 | + case CS7: |
---|
| 1122 | + newline.bDataBits = 7; |
---|
| 1123 | + break; |
---|
| 1124 | + case CS8: |
---|
| 1125 | + default: |
---|
| 1126 | + newline.bDataBits = 8; |
---|
| 1127 | + break; |
---|
| 1128 | + } |
---|
| 1129 | + /* FIXME: Needs to clear unsupported bits in the termios */ |
---|
| 1130 | + xr_usb_serial->clocal = ((termios->c_cflag & CLOCAL) != 0); |
---|
| 1131 | + |
---|
| 1132 | + if (!newline.dwDTERate) { |
---|
| 1133 | + newline.dwDTERate = xr_usb_serial->line.dwDTERate; |
---|
| 1134 | + newctrl &= ~XR_USB_SERIAL_CTRL_DTR; |
---|
| 1135 | + } else |
---|
| 1136 | + newctrl |= XR_USB_SERIAL_CTRL_DTR; |
---|
| 1137 | + |
---|
| 1138 | + if (newctrl != xr_usb_serial->ctrlout) |
---|
| 1139 | + xr_usb_serial_set_control(xr_usb_serial, xr_usb_serial->ctrlout = newctrl); |
---|
| 1140 | + |
---|
| 1141 | + xr_usb_serial_set_flow_mode(xr_usb_serial,tty,cflag);/*set the serial flow mode*/ |
---|
| 1142 | + if (xr_usb_serial->trans9) |
---|
| 1143 | + { |
---|
| 1144 | + /* Turn on wide mode if we're 9-bit transparent. */ |
---|
| 1145 | + xr_usb_serial_set_wide_mode(xr_usb_serial,1); |
---|
| 1146 | + } |
---|
| 1147 | + else if (!xr_usb_serial->preciseflags) |
---|
| 1148 | + { |
---|
| 1149 | + xr_usb_serial_set_wide_mode(xr_usb_serial,0); |
---|
| 1150 | + } |
---|
| 1151 | + |
---|
| 1152 | + |
---|
| 1153 | + if (memcmp(&xr_usb_serial->line, &newline, sizeof newline)) |
---|
| 1154 | + { |
---|
| 1155 | + memcpy(&xr_usb_serial->line, &newline, sizeof newline); |
---|
| 1156 | + dev_dbg(&xr_usb_serial->control->dev, "%s - set line: %d %d %d %d\n", |
---|
| 1157 | + __func__, |
---|
| 1158 | + le32_to_cpu(newline.dwDTERate), |
---|
| 1159 | + newline.bCharFormat, newline.bParityType, |
---|
| 1160 | + newline.bDataBits); |
---|
| 1161 | + xr_usb_serial_set_line(xr_usb_serial, &xr_usb_serial->line); |
---|
| 1162 | + } |
---|
| 1163 | + xr_usb_serial_enable(xr_usb_serial); |
---|
| 1164 | +} |
---|
| 1165 | + |
---|
| 1166 | +static const struct tty_port_operations xr_usb_serial_port_ops = { |
---|
| 1167 | + .shutdown = xr_usb_serial_port_shutdown, |
---|
| 1168 | + .activate = xr_usb_serial_port_activate, |
---|
| 1169 | + .destruct = xr_usb_serial_port_destruct, |
---|
| 1170 | +}; |
---|
| 1171 | + |
---|
| 1172 | +/* |
---|
| 1173 | + * USB probe and disconnect routines. |
---|
| 1174 | + */ |
---|
| 1175 | + |
---|
| 1176 | +/* Little helpers: write/read buffers free */ |
---|
| 1177 | +static void xr_usb_serial_write_buffers_free(struct xr_usb_serial *xr_usb_serial) |
---|
| 1178 | +{ |
---|
| 1179 | + int i; |
---|
| 1180 | + struct xr_usb_serial_wb *wb; |
---|
| 1181 | + struct usb_device *usb_dev = interface_to_usbdev(xr_usb_serial->control); |
---|
| 1182 | + |
---|
| 1183 | + for (wb = &xr_usb_serial->wb[0], i = 0; i < XR_USB_SERIAL_NW; i++, wb++) |
---|
| 1184 | + usb_free_coherent(usb_dev, xr_usb_serial->writesize, wb->buf, wb->dmah); |
---|
| 1185 | +} |
---|
| 1186 | + |
---|
| 1187 | +static void xr_usb_serial_read_buffers_free(struct xr_usb_serial *xr_usb_serial) |
---|
| 1188 | +{ |
---|
| 1189 | + struct usb_device *usb_dev = interface_to_usbdev(xr_usb_serial->control); |
---|
| 1190 | + int i; |
---|
| 1191 | + |
---|
| 1192 | + for (i = 0; i < xr_usb_serial->rx_buflimit; i++) |
---|
| 1193 | + usb_free_coherent(usb_dev, xr_usb_serial->readsize, |
---|
| 1194 | + xr_usb_serial->read_buffers[i].base, xr_usb_serial->read_buffers[i].dma); |
---|
| 1195 | +} |
---|
| 1196 | + |
---|
| 1197 | +/* Little helper: write buffers allocate */ |
---|
| 1198 | +static int xr_usb_serial_write_buffers_alloc(struct xr_usb_serial *xr_usb_serial) |
---|
| 1199 | +{ |
---|
| 1200 | + int i; |
---|
| 1201 | + struct xr_usb_serial_wb *wb; |
---|
| 1202 | + |
---|
| 1203 | + for (wb = &xr_usb_serial->wb[0], i = 0; i < XR_USB_SERIAL_NW; i++, wb++) { |
---|
| 1204 | + wb->buf = usb_alloc_coherent(xr_usb_serial->dev, xr_usb_serial->writesize, GFP_KERNEL, |
---|
| 1205 | + &wb->dmah); |
---|
| 1206 | + if (!wb->buf) { |
---|
| 1207 | + while (i != 0) { |
---|
| 1208 | + --i; |
---|
| 1209 | + --wb; |
---|
| 1210 | + usb_free_coherent(xr_usb_serial->dev, xr_usb_serial->writesize, |
---|
| 1211 | + wb->buf, wb->dmah); |
---|
| 1212 | + } |
---|
| 1213 | + return -ENOMEM; |
---|
| 1214 | + } |
---|
| 1215 | + } |
---|
| 1216 | + return 0; |
---|
| 1217 | +} |
---|
| 1218 | + |
---|
| 1219 | +static int xr_usb_serial_probe(struct usb_interface *intf, |
---|
| 1220 | + const struct usb_device_id *id) |
---|
| 1221 | +{ |
---|
| 1222 | + struct usb_cdc_union_desc *union_header = NULL; |
---|
| 1223 | + struct usb_cdc_country_functional_desc *cfd = NULL; |
---|
| 1224 | + unsigned char *buffer = intf->altsetting->extra; |
---|
| 1225 | + int buflen = intf->altsetting->extralen; |
---|
| 1226 | + struct usb_interface *control_interface; |
---|
| 1227 | + struct usb_interface *data_interface; |
---|
| 1228 | + struct usb_endpoint_descriptor *epctrl = NULL; |
---|
| 1229 | + struct usb_endpoint_descriptor *epread = NULL; |
---|
| 1230 | + struct usb_endpoint_descriptor *epwrite = NULL; |
---|
| 1231 | + struct usb_device *usb_dev = interface_to_usbdev(intf); |
---|
| 1232 | + struct xr_usb_serial *xr_usb_serial; |
---|
| 1233 | + int minor; |
---|
| 1234 | + int ctrlsize, readsize; |
---|
| 1235 | + u8 *buf; |
---|
| 1236 | + u8 ac_management_function = 0; |
---|
| 1237 | + u8 call_management_function = 0; |
---|
| 1238 | + int call_interface_num = -1; |
---|
| 1239 | + int data_interface_num = -1; |
---|
| 1240 | + unsigned long quirks; |
---|
| 1241 | + int num_rx_buf; |
---|
| 1242 | + int i; |
---|
| 1243 | + int combined_interfaces = 0; |
---|
| 1244 | + struct device *tty_dev; |
---|
| 1245 | + int rv = -ENOMEM; |
---|
| 1246 | + |
---|
| 1247 | + /* normal quirks */ |
---|
| 1248 | + quirks = (unsigned long)id->driver_info; |
---|
| 1249 | + |
---|
| 1250 | + if (quirks == IGNORE_DEVICE) |
---|
| 1251 | + return -ENODEV; |
---|
| 1252 | + |
---|
| 1253 | + num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : XR_USB_SERIAL_NR; |
---|
| 1254 | + |
---|
| 1255 | + dev_dbg(&intf->dev, "USB_device_id idVendor:%04x, idProduct %04x\n",id->idVendor,id->idProduct); |
---|
| 1256 | + |
---|
| 1257 | + /* handle quirks deadly to normal probing*/ |
---|
| 1258 | + if (quirks == NO_UNION_NORMAL) { |
---|
| 1259 | + data_interface = usb_ifnum_to_if(usb_dev, 1); |
---|
| 1260 | + control_interface = usb_ifnum_to_if(usb_dev, 0); |
---|
| 1261 | + goto skip_normal_probe; |
---|
| 1262 | + } |
---|
| 1263 | + |
---|
| 1264 | + /* normal probing*/ |
---|
| 1265 | + if (!buffer) { |
---|
| 1266 | + dev_err(&intf->dev, "Weird descriptor references\n"); |
---|
| 1267 | + return -EINVAL; |
---|
| 1268 | + } |
---|
| 1269 | + |
---|
| 1270 | + if (!buflen) { |
---|
| 1271 | + if (intf->cur_altsetting->endpoint && |
---|
| 1272 | + intf->cur_altsetting->endpoint->extralen && |
---|
| 1273 | + intf->cur_altsetting->endpoint->extra) { |
---|
| 1274 | + dev_dbg(&intf->dev, |
---|
| 1275 | + "Seeking extra descriptors on endpoint\n"); |
---|
| 1276 | + buflen = intf->cur_altsetting->endpoint->extralen; |
---|
| 1277 | + buffer = intf->cur_altsetting->endpoint->extra; |
---|
| 1278 | + } else { |
---|
| 1279 | + dev_err(&intf->dev, |
---|
| 1280 | + "Zero length descriptor references\n"); |
---|
| 1281 | + return -EINVAL; |
---|
| 1282 | + } |
---|
| 1283 | + } |
---|
| 1284 | + |
---|
| 1285 | + while (buflen > 0) { |
---|
| 1286 | + if (buffer[1] != USB_DT_CS_INTERFACE) { |
---|
| 1287 | + dev_err(&intf->dev, "skipping garbage\n"); |
---|
| 1288 | + goto next_desc; |
---|
| 1289 | + } |
---|
| 1290 | + |
---|
| 1291 | + switch (buffer[2]) { |
---|
| 1292 | + case USB_CDC_UNION_TYPE: /* we've found it */ |
---|
| 1293 | + if (union_header) { |
---|
| 1294 | + dev_err(&intf->dev, "More than one " |
---|
| 1295 | + "union descriptor, skipping ...\n"); |
---|
| 1296 | + goto next_desc; |
---|
| 1297 | + } |
---|
| 1298 | + union_header = (struct usb_cdc_union_desc *)buffer; |
---|
| 1299 | + break; |
---|
| 1300 | + case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ |
---|
| 1301 | + cfd = (struct usb_cdc_country_functional_desc *)buffer; |
---|
| 1302 | + break; |
---|
| 1303 | + case USB_CDC_HEADER_TYPE: /* maybe check version */ |
---|
| 1304 | + break; /* for now we ignore it */ |
---|
| 1305 | + case USB_CDC_ACM_TYPE: |
---|
| 1306 | + ac_management_function = buffer[3]; |
---|
| 1307 | + break; |
---|
| 1308 | + case USB_CDC_CALL_MANAGEMENT_TYPE: |
---|
| 1309 | + call_management_function = buffer[3]; |
---|
| 1310 | + call_interface_num = buffer[4]; |
---|
| 1311 | + if ((quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3) |
---|
| 1312 | + dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); |
---|
| 1313 | + break; |
---|
| 1314 | + default: |
---|
| 1315 | + /* there are LOTS more CDC descriptors that |
---|
| 1316 | + * could legitimately be found here. |
---|
| 1317 | + */ |
---|
| 1318 | + dev_dbg(&intf->dev, "Ignoring descriptor: " |
---|
| 1319 | + "type %02x, length %d\n", |
---|
| 1320 | + buffer[2], buffer[0]); |
---|
| 1321 | + break; |
---|
| 1322 | + } |
---|
| 1323 | +next_desc: |
---|
| 1324 | + buflen -= buffer[0]; |
---|
| 1325 | + buffer += buffer[0]; |
---|
| 1326 | + } |
---|
| 1327 | + |
---|
| 1328 | + if (!union_header) { |
---|
| 1329 | + if (call_interface_num > 0) { |
---|
| 1330 | + dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); |
---|
| 1331 | + /* quirks for Droids MuIn LCD */ |
---|
| 1332 | + if (quirks & NO_DATA_INTERFACE) |
---|
| 1333 | + data_interface = usb_ifnum_to_if(usb_dev, 0); |
---|
| 1334 | + else |
---|
| 1335 | + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); |
---|
| 1336 | + control_interface = intf; |
---|
| 1337 | + } else { |
---|
| 1338 | + if (intf->cur_altsetting->desc.bNumEndpoints != 3) { |
---|
| 1339 | + dev_dbg(&intf->dev,"No union descriptor, giving up\n"); |
---|
| 1340 | + return -ENODEV; |
---|
| 1341 | + } else { |
---|
| 1342 | + dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n"); |
---|
| 1343 | + combined_interfaces = 1; |
---|
| 1344 | + control_interface = data_interface = intf; |
---|
| 1345 | + goto look_for_collapsed_interface; |
---|
| 1346 | + } |
---|
| 1347 | + } |
---|
| 1348 | + } else { |
---|
| 1349 | + control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); |
---|
| 1350 | + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); |
---|
| 1351 | + if (!control_interface || !data_interface) { |
---|
| 1352 | + dev_dbg(&intf->dev, "no interfaces\n"); |
---|
| 1353 | + return -ENODEV; |
---|
| 1354 | + } |
---|
| 1355 | + } |
---|
| 1356 | + |
---|
| 1357 | + if (data_interface_num != call_interface_num) |
---|
| 1358 | + dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); |
---|
| 1359 | + |
---|
| 1360 | + if (control_interface == data_interface) { |
---|
| 1361 | + /* some broken devices designed for windows work this way */ |
---|
| 1362 | + dev_warn(&intf->dev,"Control and data interfaces are not separated!\n"); |
---|
| 1363 | + combined_interfaces = 1; |
---|
| 1364 | + /* a popular other OS doesn't use it */ |
---|
| 1365 | + quirks |= NO_CAP_LINE; |
---|
| 1366 | + if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) { |
---|
| 1367 | + dev_err(&intf->dev, "This needs exactly 3 endpoints\n"); |
---|
| 1368 | + return -EINVAL; |
---|
| 1369 | + } |
---|
| 1370 | +look_for_collapsed_interface: |
---|
| 1371 | + for (i = 0; i < 3; i++) { |
---|
| 1372 | + struct usb_endpoint_descriptor *ep; |
---|
| 1373 | + ep = &data_interface->cur_altsetting->endpoint[i].desc; |
---|
| 1374 | + |
---|
| 1375 | + if (usb_endpoint_is_int_in(ep)) |
---|
| 1376 | + epctrl = ep; |
---|
| 1377 | + else if (usb_endpoint_is_bulk_out(ep)) |
---|
| 1378 | + epwrite = ep; |
---|
| 1379 | + else if (usb_endpoint_is_bulk_in(ep)) |
---|
| 1380 | + epread = ep; |
---|
| 1381 | + else |
---|
| 1382 | + return -EINVAL; |
---|
| 1383 | + } |
---|
| 1384 | + if (!epctrl || !epread || !epwrite) |
---|
| 1385 | + return -ENODEV; |
---|
| 1386 | + else |
---|
| 1387 | + goto made_compressed_probe; |
---|
| 1388 | + } |
---|
| 1389 | + |
---|
| 1390 | +skip_normal_probe: |
---|
| 1391 | + |
---|
| 1392 | + /*workaround for switched interfaces */ |
---|
| 1393 | + if (data_interface->cur_altsetting->desc.bInterfaceClass |
---|
| 1394 | + != CDC_DATA_INTERFACE_TYPE) { |
---|
| 1395 | + if (control_interface->cur_altsetting->desc.bInterfaceClass |
---|
| 1396 | + == CDC_DATA_INTERFACE_TYPE) { |
---|
| 1397 | + struct usb_interface *t; |
---|
| 1398 | + dev_dbg(&intf->dev, |
---|
| 1399 | + "Your device has switched interfaces.\n"); |
---|
| 1400 | + t = control_interface; |
---|
| 1401 | + control_interface = data_interface; |
---|
| 1402 | + data_interface = t; |
---|
| 1403 | + } else { |
---|
| 1404 | + return -EINVAL; |
---|
| 1405 | + } |
---|
| 1406 | + } |
---|
| 1407 | + |
---|
| 1408 | + /* Accept probe requests only for the control interface */ |
---|
| 1409 | + if (!combined_interfaces && intf != control_interface) |
---|
| 1410 | + return -ENODEV; |
---|
| 1411 | + |
---|
| 1412 | + if (!combined_interfaces && usb_interface_claimed(data_interface)) { |
---|
| 1413 | + /* valid in this context */ |
---|
| 1414 | + dev_dbg(&intf->dev, "The data interface isn't available\n"); |
---|
| 1415 | + return -EBUSY; |
---|
| 1416 | + } |
---|
| 1417 | + |
---|
| 1418 | + |
---|
| 1419 | + if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 || |
---|
| 1420 | + control_interface->cur_altsetting->desc.bNumEndpoints == 0) |
---|
| 1421 | + return -EINVAL; |
---|
| 1422 | + |
---|
| 1423 | + epctrl = &control_interface->cur_altsetting->endpoint[0].desc; |
---|
| 1424 | + epread = &data_interface->cur_altsetting->endpoint[0].desc; |
---|
| 1425 | + epwrite = &data_interface->cur_altsetting->endpoint[1].desc; |
---|
| 1426 | + |
---|
| 1427 | + |
---|
| 1428 | + /* workaround for switched endpoints */ |
---|
| 1429 | + if (!usb_endpoint_dir_in(epread)) { |
---|
| 1430 | + /* descriptors are swapped */ |
---|
| 1431 | + struct usb_endpoint_descriptor *t; |
---|
| 1432 | + dev_dbg(&intf->dev, |
---|
| 1433 | + "The data interface has switched endpoints\n"); |
---|
| 1434 | + t = epread; |
---|
| 1435 | + epread = epwrite; |
---|
| 1436 | + epwrite = t; |
---|
| 1437 | + } |
---|
| 1438 | +made_compressed_probe: |
---|
| 1439 | + dev_dbg(&intf->dev, "interfaces are valid\n"); |
---|
| 1440 | + |
---|
| 1441 | + xr_usb_serial = kzalloc(sizeof(struct xr_usb_serial), GFP_KERNEL); |
---|
| 1442 | + if (xr_usb_serial == NULL) { |
---|
| 1443 | + dev_err(&intf->dev, "out of memory (xr_usb_serial kzalloc)\n"); |
---|
| 1444 | + goto alloc_fail; |
---|
| 1445 | + } |
---|
| 1446 | + |
---|
| 1447 | + minor = xr_usb_serial_alloc_minor(xr_usb_serial); |
---|
| 1448 | + if (minor == XR_USB_SERIAL_TTY_MINORS) { |
---|
| 1449 | + dev_err(&intf->dev, "no more free xr_usb_serial devices\n"); |
---|
| 1450 | + kfree(xr_usb_serial); |
---|
| 1451 | + return -ENODEV; |
---|
| 1452 | + } |
---|
| 1453 | + |
---|
| 1454 | + ctrlsize = usb_endpoint_maxp(epctrl); |
---|
| 1455 | + readsize = usb_endpoint_maxp(epread) * |
---|
| 1456 | + (quirks == SINGLE_RX_URB ? 1 : 2); |
---|
| 1457 | + xr_usb_serial->combined_interfaces = combined_interfaces; |
---|
| 1458 | + xr_usb_serial->writesize = usb_endpoint_maxp(epwrite) * 20; |
---|
| 1459 | + xr_usb_serial->control = control_interface; |
---|
| 1460 | + xr_usb_serial->data = data_interface; |
---|
| 1461 | + xr_usb_serial->minor = minor; |
---|
| 1462 | + xr_usb_serial->dev = usb_dev; |
---|
| 1463 | + xr_usb_serial->ctrl_caps = ac_management_function; |
---|
| 1464 | + if (quirks & NO_CAP_LINE) |
---|
| 1465 | + xr_usb_serial->ctrl_caps &= ~USB_CDC_CAP_LINE; |
---|
| 1466 | + xr_usb_serial->ctrlsize = ctrlsize; |
---|
| 1467 | + xr_usb_serial->readsize = readsize; |
---|
| 1468 | + xr_usb_serial->rx_buflimit = num_rx_buf; |
---|
| 1469 | + INIT_WORK(&xr_usb_serial->work, xr_usb_serial_softint); |
---|
| 1470 | + spin_lock_init(&xr_usb_serial->write_lock); |
---|
| 1471 | + spin_lock_init(&xr_usb_serial->read_lock); |
---|
| 1472 | + mutex_init(&xr_usb_serial->mutex); |
---|
| 1473 | + xr_usb_serial->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); |
---|
| 1474 | + xr_usb_serial->is_int_ep = usb_endpoint_xfer_int(epread); |
---|
| 1475 | + if (xr_usb_serial->is_int_ep) |
---|
| 1476 | + xr_usb_serial->bInterval = epread->bInterval; |
---|
| 1477 | + tty_port_init(&xr_usb_serial->port); |
---|
| 1478 | + xr_usb_serial->port.ops = &xr_usb_serial_port_ops; |
---|
| 1479 | + xr_usb_serial->DeviceVendor = id->idVendor; |
---|
| 1480 | + xr_usb_serial->DeviceProduct = id->idProduct; |
---|
| 1481 | + #if 0 |
---|
| 1482 | + if((xr_usb_serial->DeviceProduct&0xfff0) == 0x1410) |
---|
| 1483 | + {//map the serial port A B C D to blocknum 0 1 2 3 for the xr21v141x device |
---|
| 1484 | + xr_usb_serial->channel = epwrite->bEndpointAddress - 1; |
---|
| 1485 | + } |
---|
| 1486 | + else if((xr_usb_serial->DeviceProduct&0xfff0) == 0x1420) |
---|
| 1487 | + {//map the serial port A B C D to blocknum 0 2 4 6 for the xr21B142x device |
---|
| 1488 | + xr_usb_serial->channel = (epwrite->bEndpointAddress - 4)*2; |
---|
| 1489 | + } |
---|
| 1490 | + else |
---|
| 1491 | + { |
---|
| 1492 | + xr_usb_serial->channel = epwrite->bEndpointAddress; |
---|
| 1493 | + } |
---|
| 1494 | + #else |
---|
| 1495 | + xr_usb_serial->channel = epwrite->bEndpointAddress; |
---|
| 1496 | + dev_dbg(&intf->dev, "epwrite->bEndpointAddress =%d\n",epwrite->bEndpointAddress); |
---|
| 1497 | + #endif |
---|
| 1498 | + buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &xr_usb_serial->ctrl_dma); |
---|
| 1499 | + if (!buf) { |
---|
| 1500 | + dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n"); |
---|
| 1501 | + goto alloc_fail2; |
---|
| 1502 | + } |
---|
| 1503 | + xr_usb_serial->ctrl_buffer = buf; |
---|
| 1504 | + |
---|
| 1505 | + if (xr_usb_serial_write_buffers_alloc(xr_usb_serial) < 0) { |
---|
| 1506 | + dev_err(&intf->dev, "out of memory (write buffer alloc)\n"); |
---|
| 1507 | + goto alloc_fail4; |
---|
| 1508 | + } |
---|
| 1509 | + |
---|
| 1510 | + xr_usb_serial->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); |
---|
| 1511 | + if (!xr_usb_serial->ctrlurb) { |
---|
| 1512 | + dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); |
---|
| 1513 | + goto alloc_fail5; |
---|
| 1514 | + } |
---|
| 1515 | + for (i = 0; i < num_rx_buf; i++) { |
---|
| 1516 | + struct xr_usb_serial_rb *rb = &(xr_usb_serial->read_buffers[i]); |
---|
| 1517 | + struct urb *urb; |
---|
| 1518 | + |
---|
| 1519 | + rb->base = usb_alloc_coherent(xr_usb_serial->dev, readsize, GFP_KERNEL, |
---|
| 1520 | + &rb->dma); |
---|
| 1521 | + if (!rb->base) { |
---|
| 1522 | + dev_err(&intf->dev, "out of memory " |
---|
| 1523 | + "(read bufs usb_alloc_coherent)\n"); |
---|
| 1524 | + goto alloc_fail6; |
---|
| 1525 | + } |
---|
| 1526 | + rb->index = i; |
---|
| 1527 | + rb->instance = xr_usb_serial; |
---|
| 1528 | + |
---|
| 1529 | + urb = usb_alloc_urb(0, GFP_KERNEL); |
---|
| 1530 | + if (!urb) { |
---|
| 1531 | + dev_err(&intf->dev, |
---|
| 1532 | + "out of memory (read urbs usb_alloc_urb)\n"); |
---|
| 1533 | + goto alloc_fail6; |
---|
| 1534 | + } |
---|
| 1535 | + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
---|
| 1536 | + urb->transfer_dma = rb->dma; |
---|
| 1537 | + if (xr_usb_serial->is_int_ep) { |
---|
| 1538 | + usb_fill_int_urb(urb, xr_usb_serial->dev, |
---|
| 1539 | + xr_usb_serial->rx_endpoint, |
---|
| 1540 | + rb->base, |
---|
| 1541 | + xr_usb_serial->readsize, |
---|
| 1542 | + xr_usb_serial_read_bulk_callback, rb, |
---|
| 1543 | + xr_usb_serial->bInterval); |
---|
| 1544 | + } else { |
---|
| 1545 | + usb_fill_bulk_urb(urb, xr_usb_serial->dev, |
---|
| 1546 | + xr_usb_serial->rx_endpoint, |
---|
| 1547 | + rb->base, |
---|
| 1548 | + xr_usb_serial->readsize, |
---|
| 1549 | + xr_usb_serial_read_bulk_callback, rb); |
---|
| 1550 | + } |
---|
| 1551 | + |
---|
| 1552 | + xr_usb_serial->read_urbs[i] = urb; |
---|
| 1553 | + __set_bit(i, &xr_usb_serial->read_urbs_free); |
---|
| 1554 | + } |
---|
| 1555 | + for (i = 0; i < XR_USB_SERIAL_NW; i++) { |
---|
| 1556 | + struct xr_usb_serial_wb *snd = &(xr_usb_serial->wb[i]); |
---|
| 1557 | + |
---|
| 1558 | + snd->urb = usb_alloc_urb(0, GFP_KERNEL); |
---|
| 1559 | + if (snd->urb == NULL) { |
---|
| 1560 | + dev_err(&intf->dev, |
---|
| 1561 | + "out of memory (write urbs usb_alloc_urb)\n"); |
---|
| 1562 | + goto alloc_fail7; |
---|
| 1563 | + } |
---|
| 1564 | + |
---|
| 1565 | + if (usb_endpoint_xfer_int(epwrite)) |
---|
| 1566 | + usb_fill_int_urb(snd->urb, usb_dev, |
---|
| 1567 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) |
---|
| 1568 | + usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), |
---|
| 1569 | +#else |
---|
| 1570 | + usb_sndintpipe(usb_dev, epwrite->bEndpointAddress), |
---|
| 1571 | +#endif |
---|
| 1572 | + NULL, xr_usb_serial->writesize, xr_usb_serial_write_bulk, snd, epwrite->bInterval); |
---|
| 1573 | + else |
---|
| 1574 | + usb_fill_bulk_urb(snd->urb, usb_dev, |
---|
| 1575 | + usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), |
---|
| 1576 | + NULL, xr_usb_serial->writesize, xr_usb_serial_write_bulk, snd); |
---|
| 1577 | + snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
---|
| 1578 | + snd->instance = xr_usb_serial; |
---|
| 1579 | + } |
---|
| 1580 | + |
---|
| 1581 | + usb_set_intfdata(intf, xr_usb_serial); |
---|
| 1582 | + |
---|
| 1583 | + i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); |
---|
| 1584 | + if (i < 0) |
---|
| 1585 | + goto alloc_fail7; |
---|
| 1586 | + |
---|
| 1587 | + if (cfd) { /* export the country data */ |
---|
| 1588 | + xr_usb_serial->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); |
---|
| 1589 | + if (!xr_usb_serial->country_codes) |
---|
| 1590 | + goto skip_countries; |
---|
| 1591 | + xr_usb_serial->country_code_size = cfd->bLength - 4; |
---|
| 1592 | + memcpy(xr_usb_serial->country_codes, (u8 *)&cfd->wCountyCode0, |
---|
| 1593 | + cfd->bLength - 4); |
---|
| 1594 | + xr_usb_serial->country_rel_date = cfd->iCountryCodeRelDate; |
---|
| 1595 | + |
---|
| 1596 | + i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); |
---|
| 1597 | + if (i < 0) { |
---|
| 1598 | + kfree(xr_usb_serial->country_codes); |
---|
| 1599 | + xr_usb_serial->country_codes = NULL; |
---|
| 1600 | + xr_usb_serial->country_code_size = 0; |
---|
| 1601 | + goto skip_countries; |
---|
| 1602 | + } |
---|
| 1603 | + |
---|
| 1604 | + i = device_create_file(&intf->dev, |
---|
| 1605 | + &dev_attr_iCountryCodeRelDate); |
---|
| 1606 | + if (i < 0) { |
---|
| 1607 | + device_remove_file(&intf->dev, &dev_attr_wCountryCodes); |
---|
| 1608 | + kfree(xr_usb_serial->country_codes); |
---|
| 1609 | + xr_usb_serial->country_codes = NULL; |
---|
| 1610 | + xr_usb_serial->country_code_size = 0; |
---|
| 1611 | + goto skip_countries; |
---|
| 1612 | + } |
---|
| 1613 | + } |
---|
| 1614 | + |
---|
| 1615 | +skip_countries: |
---|
| 1616 | + usb_fill_int_urb(xr_usb_serial->ctrlurb, usb_dev, |
---|
| 1617 | + usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), |
---|
| 1618 | + xr_usb_serial->ctrl_buffer, ctrlsize, xr_usb_serial_ctrl_irq, xr_usb_serial, |
---|
| 1619 | + /* works around buggy devices */ |
---|
| 1620 | + epctrl->bInterval ? epctrl->bInterval : 0xff); |
---|
| 1621 | + xr_usb_serial->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
---|
| 1622 | + xr_usb_serial->ctrlurb->transfer_dma = xr_usb_serial->ctrl_dma; |
---|
| 1623 | + |
---|
| 1624 | + dev_info(&intf->dev, "ttyXR_USB_SERIAL%d: USB XR_USB_SERIAL device\n", minor); |
---|
| 1625 | + |
---|
| 1626 | + xr_usb_serial_pre_setup(xr_usb_serial); |
---|
| 1627 | + |
---|
| 1628 | + xr_usb_serial_set_control(xr_usb_serial, xr_usb_serial->ctrlout); |
---|
| 1629 | + |
---|
| 1630 | + xr_usb_serial->line.dwDTERate = cpu_to_le32(9600); |
---|
| 1631 | + xr_usb_serial->line.bDataBits = 8; |
---|
| 1632 | + xr_usb_serial_set_line(xr_usb_serial, &xr_usb_serial->line); |
---|
| 1633 | + |
---|
| 1634 | + usb_driver_claim_interface(&xr_usb_serial_driver, data_interface, xr_usb_serial); |
---|
| 1635 | + usb_set_intfdata(data_interface, xr_usb_serial); |
---|
| 1636 | + |
---|
| 1637 | + usb_get_intf(control_interface); |
---|
| 1638 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) |
---|
| 1639 | + tty_register_device(xr_usb_serial_tty_driver, minor, &control_interface->dev); |
---|
| 1640 | +#else |
---|
| 1641 | + tty_dev = tty_port_register_device(&xr_usb_serial->port, xr_usb_serial_tty_driver, minor, |
---|
| 1642 | + &control_interface->dev); |
---|
| 1643 | + if (IS_ERR(tty_dev)) { |
---|
| 1644 | + rv = PTR_ERR(tty_dev); |
---|
| 1645 | + goto alloc_fail8; |
---|
| 1646 | + } |
---|
| 1647 | +#endif |
---|
| 1648 | + |
---|
| 1649 | + return 0; |
---|
| 1650 | +alloc_fail8: |
---|
| 1651 | + if (xr_usb_serial->country_codes) { |
---|
| 1652 | + device_remove_file(&xr_usb_serial->control->dev, |
---|
| 1653 | + &dev_attr_wCountryCodes); |
---|
| 1654 | + device_remove_file(&xr_usb_serial->control->dev, |
---|
| 1655 | + &dev_attr_iCountryCodeRelDate); |
---|
| 1656 | + } |
---|
| 1657 | + device_remove_file(&xr_usb_serial->control->dev, &dev_attr_bmCapabilities); |
---|
| 1658 | +alloc_fail7: |
---|
| 1659 | + usb_set_intfdata(intf, NULL); |
---|
| 1660 | + for (i = 0; i < XR_USB_SERIAL_NW; i++) |
---|
| 1661 | + usb_free_urb(xr_usb_serial->wb[i].urb); |
---|
| 1662 | +alloc_fail6: |
---|
| 1663 | + for (i = 0; i < num_rx_buf; i++) |
---|
| 1664 | + usb_free_urb(xr_usb_serial->read_urbs[i]); |
---|
| 1665 | + xr_usb_serial_read_buffers_free(xr_usb_serial); |
---|
| 1666 | + usb_free_urb(xr_usb_serial->ctrlurb); |
---|
| 1667 | +alloc_fail5: |
---|
| 1668 | + xr_usb_serial_write_buffers_free(xr_usb_serial); |
---|
| 1669 | +alloc_fail4: |
---|
| 1670 | + usb_free_coherent(usb_dev, ctrlsize, xr_usb_serial->ctrl_buffer, xr_usb_serial->ctrl_dma); |
---|
| 1671 | +alloc_fail2: |
---|
| 1672 | + xr_usb_serial_release_minor(xr_usb_serial); |
---|
| 1673 | + kfree(xr_usb_serial); |
---|
| 1674 | +alloc_fail: |
---|
| 1675 | + return rv; |
---|
| 1676 | +} |
---|
| 1677 | + |
---|
| 1678 | +static void stop_data_traffic(struct xr_usb_serial *xr_usb_serial) |
---|
| 1679 | +{ |
---|
| 1680 | + int i; |
---|
| 1681 | + |
---|
| 1682 | + dev_dbg(&xr_usb_serial->control->dev, "%s\n", __func__); |
---|
| 1683 | + |
---|
| 1684 | + usb_kill_urb(xr_usb_serial->ctrlurb); |
---|
| 1685 | + for (i = 0; i < XR_USB_SERIAL_NW; i++) |
---|
| 1686 | + usb_kill_urb(xr_usb_serial->wb[i].urb); |
---|
| 1687 | + for (i = 0; i < xr_usb_serial->rx_buflimit; i++) |
---|
| 1688 | + usb_kill_urb(xr_usb_serial->read_urbs[i]); |
---|
| 1689 | + |
---|
| 1690 | + cancel_work_sync(&xr_usb_serial->work); |
---|
| 1691 | +} |
---|
| 1692 | + |
---|
| 1693 | +static void xr_usb_serial_disconnect(struct usb_interface *intf) |
---|
| 1694 | +{ |
---|
| 1695 | + struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf); |
---|
| 1696 | + struct usb_device *usb_dev = interface_to_usbdev(intf); |
---|
| 1697 | + struct tty_struct *tty; |
---|
| 1698 | + int i; |
---|
| 1699 | + |
---|
| 1700 | + dev_dbg(&intf->dev, "%s\n", __func__); |
---|
| 1701 | + |
---|
| 1702 | + /* sibling interface is already cleaning up */ |
---|
| 1703 | + if (!xr_usb_serial) |
---|
| 1704 | + return; |
---|
| 1705 | + |
---|
| 1706 | + mutex_lock(&xr_usb_serial->mutex); |
---|
| 1707 | + xr_usb_serial->disconnected = true; |
---|
| 1708 | + if (xr_usb_serial->country_codes) { |
---|
| 1709 | + device_remove_file(&xr_usb_serial->control->dev, |
---|
| 1710 | + &dev_attr_wCountryCodes); |
---|
| 1711 | + device_remove_file(&xr_usb_serial->control->dev, |
---|
| 1712 | + &dev_attr_iCountryCodeRelDate); |
---|
| 1713 | + } |
---|
| 1714 | + device_remove_file(&xr_usb_serial->control->dev, &dev_attr_bmCapabilities); |
---|
| 1715 | + usb_set_intfdata(xr_usb_serial->control, NULL); |
---|
| 1716 | + usb_set_intfdata(xr_usb_serial->data, NULL); |
---|
| 1717 | + mutex_unlock(&xr_usb_serial->mutex); |
---|
| 1718 | + |
---|
| 1719 | + tty = tty_port_tty_get(&xr_usb_serial->port); |
---|
| 1720 | + if (tty) { |
---|
| 1721 | + tty_vhangup(tty); |
---|
| 1722 | + tty_kref_put(tty); |
---|
| 1723 | + } |
---|
| 1724 | + stop_data_traffic(xr_usb_serial); |
---|
| 1725 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 0) |
---|
| 1726 | + tty_unregister_device(xr_usb_serial_tty_driver, xr_usb_serial->minor); |
---|
| 1727 | +#endif |
---|
| 1728 | + |
---|
| 1729 | + usb_free_urb(xr_usb_serial->ctrlurb); |
---|
| 1730 | + for (i = 0; i < XR_USB_SERIAL_NW; i++) |
---|
| 1731 | + usb_free_urb(xr_usb_serial->wb[i].urb); |
---|
| 1732 | + for (i = 0; i < xr_usb_serial->rx_buflimit; i++) |
---|
| 1733 | + usb_free_urb(xr_usb_serial->read_urbs[i]); |
---|
| 1734 | + xr_usb_serial_write_buffers_free(xr_usb_serial); |
---|
| 1735 | + usb_free_coherent(usb_dev, xr_usb_serial->ctrlsize, xr_usb_serial->ctrl_buffer, xr_usb_serial->ctrl_dma); |
---|
| 1736 | + xr_usb_serial_read_buffers_free(xr_usb_serial); |
---|
| 1737 | + |
---|
| 1738 | + if (!xr_usb_serial->combined_interfaces) |
---|
| 1739 | + usb_driver_release_interface(&xr_usb_serial_driver, intf == xr_usb_serial->control ? |
---|
| 1740 | + xr_usb_serial->data : xr_usb_serial->control); |
---|
| 1741 | + |
---|
| 1742 | + tty_port_put(&xr_usb_serial->port); |
---|
| 1743 | +} |
---|
| 1744 | + |
---|
| 1745 | +#ifdef CONFIG_PM |
---|
| 1746 | +static int xr_usb_serial_suspend(struct usb_interface *intf, pm_message_t message) |
---|
| 1747 | +{ |
---|
| 1748 | + struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf); |
---|
| 1749 | + int cnt; |
---|
| 1750 | + |
---|
| 1751 | + if (PMSG_IS_AUTO(message)) { |
---|
| 1752 | + int b; |
---|
| 1753 | + |
---|
| 1754 | + spin_lock_irq(&xr_usb_serial->write_lock); |
---|
| 1755 | + b = xr_usb_serial->transmitting; |
---|
| 1756 | + spin_unlock_irq(&xr_usb_serial->write_lock); |
---|
| 1757 | + if (b) |
---|
| 1758 | + return -EBUSY; |
---|
| 1759 | + } |
---|
| 1760 | + |
---|
| 1761 | + spin_lock_irq(&xr_usb_serial->read_lock); |
---|
| 1762 | + spin_lock(&xr_usb_serial->write_lock); |
---|
| 1763 | + cnt = xr_usb_serial->susp_count++; |
---|
| 1764 | + spin_unlock(&xr_usb_serial->write_lock); |
---|
| 1765 | + spin_unlock_irq(&xr_usb_serial->read_lock); |
---|
| 1766 | + |
---|
| 1767 | + if (cnt) |
---|
| 1768 | + return 0; |
---|
| 1769 | + |
---|
| 1770 | + if (test_bit(ASYNCB_INITIALIZED, &xr_usb_serial->port.flags)) |
---|
| 1771 | + stop_data_traffic(xr_usb_serial); |
---|
| 1772 | + |
---|
| 1773 | + return 0; |
---|
| 1774 | +} |
---|
| 1775 | + |
---|
| 1776 | +static int xr_usb_serial_resume(struct usb_interface *intf) |
---|
| 1777 | +{ |
---|
| 1778 | + struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf); |
---|
| 1779 | + struct xr_usb_serial_wb *wb; |
---|
| 1780 | + int rv = 0; |
---|
| 1781 | + int cnt; |
---|
| 1782 | + |
---|
| 1783 | + spin_lock_irq(&xr_usb_serial->read_lock); |
---|
| 1784 | + xr_usb_serial->susp_count -= 1; |
---|
| 1785 | + cnt = xr_usb_serial->susp_count; |
---|
| 1786 | + spin_unlock_irq(&xr_usb_serial->read_lock); |
---|
| 1787 | + |
---|
| 1788 | + if (cnt) |
---|
| 1789 | + return 0; |
---|
| 1790 | + |
---|
| 1791 | + if (test_bit(ASYNCB_INITIALIZED, &xr_usb_serial->port.flags)) { |
---|
| 1792 | + rv = usb_submit_urb(xr_usb_serial->ctrlurb, GFP_NOIO); |
---|
| 1793 | + |
---|
| 1794 | + spin_lock_irq(&xr_usb_serial->write_lock); |
---|
| 1795 | + if (xr_usb_serial->delayed_wb) { |
---|
| 1796 | + wb = xr_usb_serial->delayed_wb; |
---|
| 1797 | + xr_usb_serial->delayed_wb = NULL; |
---|
| 1798 | + spin_unlock_irq(&xr_usb_serial->write_lock); |
---|
| 1799 | + xr_usb_serial_start_wb(xr_usb_serial, wb); |
---|
| 1800 | + } else { |
---|
| 1801 | + spin_unlock_irq(&xr_usb_serial->write_lock); |
---|
| 1802 | + } |
---|
| 1803 | + |
---|
| 1804 | + /* |
---|
| 1805 | + * delayed error checking because we must |
---|
| 1806 | + * do the write path at all cost |
---|
| 1807 | + */ |
---|
| 1808 | + if (rv < 0) |
---|
| 1809 | + goto err_out; |
---|
| 1810 | + |
---|
| 1811 | + rv = xr_usb_serial_submit_read_urbs(xr_usb_serial, GFP_NOIO); |
---|
| 1812 | + } |
---|
| 1813 | + |
---|
| 1814 | +err_out: |
---|
| 1815 | + return rv; |
---|
| 1816 | +} |
---|
| 1817 | + |
---|
| 1818 | +static int xr_usb_serial_reset_resume(struct usb_interface *intf) |
---|
| 1819 | +{ |
---|
| 1820 | + struct xr_usb_serial *xr_usb_serial = usb_get_intfdata(intf); |
---|
| 1821 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0) |
---|
| 1822 | +#else |
---|
| 1823 | + struct tty_struct *tty; |
---|
| 1824 | +#endif |
---|
| 1825 | + if (test_bit(ASYNCB_INITIALIZED, &xr_usb_serial->port.flags)){ |
---|
| 1826 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 9, 0) |
---|
| 1827 | + tty_port_tty_hangup(&xr_usb_serial->port, false); |
---|
| 1828 | +#else |
---|
| 1829 | + tty = tty_port_tty_get(&xr_usb_serial->port); |
---|
| 1830 | + if (tty) { |
---|
| 1831 | + tty_hangup(tty); |
---|
| 1832 | + tty_kref_put(tty); |
---|
| 1833 | + } |
---|
| 1834 | +#endif |
---|
| 1835 | + } |
---|
| 1836 | + return xr_usb_serial_resume(intf); |
---|
| 1837 | +} |
---|
| 1838 | + |
---|
| 1839 | +#endif /* CONFIG_PM */ |
---|
| 1840 | + |
---|
| 1841 | +/* |
---|
| 1842 | + * USB driver structure. |
---|
| 1843 | + */ |
---|
| 1844 | +static const struct usb_device_id xr_usb_serial_ids[] = { |
---|
| 1845 | + { USB_DEVICE(0x04e2, 0x1410)}, |
---|
| 1846 | + { USB_DEVICE(0x04e2, 0x1411)}, |
---|
| 1847 | + { USB_DEVICE(0x04e2, 0x1412)}, |
---|
| 1848 | + { USB_DEVICE(0x04e2, 0x1414)}, |
---|
| 1849 | + { USB_DEVICE(0x04e2, 0x1420)}, |
---|
| 1850 | + { USB_DEVICE(0x04e2, 0x1421)}, |
---|
| 1851 | + { USB_DEVICE(0x04e2, 0x1422)}, |
---|
| 1852 | + { USB_DEVICE(0x04e2, 0x1424)}, |
---|
| 1853 | + { USB_DEVICE(0x04e2, 0x1400)}, |
---|
| 1854 | + { USB_DEVICE(0x04e2, 0x1401)}, |
---|
| 1855 | + { USB_DEVICE(0x04e2, 0x1402)}, |
---|
| 1856 | + { USB_DEVICE(0x04e2, 0x1403)}, |
---|
| 1857 | + { } |
---|
| 1858 | +}; |
---|
| 1859 | + |
---|
| 1860 | +MODULE_DEVICE_TABLE(usb, xr_usb_serial_ids); |
---|
| 1861 | + |
---|
| 1862 | +static struct usb_driver xr_usb_serial_driver = { |
---|
| 1863 | + .name = "cdc_xr_usb_serial", |
---|
| 1864 | + .probe = xr_usb_serial_probe, |
---|
| 1865 | + .disconnect = xr_usb_serial_disconnect, |
---|
| 1866 | +#ifdef CONFIG_PM |
---|
| 1867 | + .suspend = xr_usb_serial_suspend, |
---|
| 1868 | + .resume = xr_usb_serial_resume, |
---|
| 1869 | + .reset_resume = xr_usb_serial_reset_resume, |
---|
| 1870 | +#endif |
---|
| 1871 | + .id_table = xr_usb_serial_ids, |
---|
| 1872 | +#ifdef CONFIG_PM |
---|
| 1873 | + .supports_autosuspend = 1, |
---|
| 1874 | +#endif |
---|
| 1875 | + .disable_hub_initiated_lpm = 1, |
---|
| 1876 | +}; |
---|
| 1877 | + |
---|
| 1878 | +/* |
---|
| 1879 | + * TTY driver structures. |
---|
| 1880 | + */ |
---|
| 1881 | + |
---|
| 1882 | +static const struct tty_operations xr_usb_serial_ops = { |
---|
| 1883 | + .install = xr_usb_serial_tty_install, |
---|
| 1884 | + .open = xr_usb_serial_tty_open, |
---|
| 1885 | + .close = xr_usb_serial_tty_close, |
---|
| 1886 | + .cleanup = xr_usb_serial_tty_cleanup, |
---|
| 1887 | + .hangup = xr_usb_serial_tty_hangup, |
---|
| 1888 | + .write = xr_usb_serial_tty_write, |
---|
| 1889 | + .write_room = xr_usb_serial_tty_write_room, |
---|
| 1890 | + .ioctl = xr_usb_serial_tty_ioctl, |
---|
| 1891 | + .throttle = xr_usb_serial_tty_throttle, |
---|
| 1892 | + .unthrottle = xr_usb_serial_tty_unthrottle, |
---|
| 1893 | + .chars_in_buffer = xr_usb_serial_tty_chars_in_buffer, |
---|
| 1894 | + .break_ctl = xr_usb_serial_tty_break_ctl, |
---|
| 1895 | + .set_termios = xr_usb_serial_tty_set_termios, |
---|
| 1896 | + .tiocmget = xr_usb_serial_tty_tiocmget, |
---|
| 1897 | + .tiocmset = xr_usb_serial_tty_tiocmset, |
---|
| 1898 | +}; |
---|
| 1899 | + |
---|
| 1900 | +/* |
---|
| 1901 | + * Init / exit. |
---|
| 1902 | + */ |
---|
| 1903 | + |
---|
| 1904 | +static int __init xr_usb_serial_init(void) |
---|
| 1905 | +{ |
---|
| 1906 | + int retval; |
---|
| 1907 | + xr_usb_serial_tty_driver = alloc_tty_driver(XR_USB_SERIAL_TTY_MINORS); |
---|
| 1908 | + if (!xr_usb_serial_tty_driver) |
---|
| 1909 | + return -ENOMEM; |
---|
| 1910 | + xr_usb_serial_tty_driver->driver_name = "xr_usb_serial", |
---|
| 1911 | + xr_usb_serial_tty_driver->name = "ttyXRUSB", |
---|
| 1912 | + xr_usb_serial_tty_driver->major = XR_USB_SERIAL_TTY_MAJOR, |
---|
| 1913 | + xr_usb_serial_tty_driver->minor_start = 0, |
---|
| 1914 | + xr_usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, |
---|
| 1915 | + xr_usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL, |
---|
| 1916 | + xr_usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; |
---|
| 1917 | + xr_usb_serial_tty_driver->init_termios = tty_std_termios; |
---|
| 1918 | + xr_usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | |
---|
| 1919 | + HUPCL | CLOCAL; |
---|
| 1920 | + tty_set_operations(xr_usb_serial_tty_driver, &xr_usb_serial_ops); |
---|
| 1921 | + |
---|
| 1922 | + retval = tty_register_driver(xr_usb_serial_tty_driver); |
---|
| 1923 | + if (retval) { |
---|
| 1924 | + put_tty_driver(xr_usb_serial_tty_driver); |
---|
| 1925 | + return retval; |
---|
| 1926 | + } |
---|
| 1927 | + |
---|
| 1928 | + retval = usb_register(&xr_usb_serial_driver); |
---|
| 1929 | + if (retval) { |
---|
| 1930 | + tty_unregister_driver(xr_usb_serial_tty_driver); |
---|
| 1931 | + put_tty_driver(xr_usb_serial_tty_driver); |
---|
| 1932 | + return retval; |
---|
| 1933 | + } |
---|
| 1934 | + |
---|
| 1935 | + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); |
---|
| 1936 | + |
---|
| 1937 | + return 0; |
---|
| 1938 | +} |
---|
| 1939 | + |
---|
| 1940 | +static void __exit xr_usb_serial_exit(void) |
---|
| 1941 | +{ |
---|
| 1942 | + usb_deregister(&xr_usb_serial_driver); |
---|
| 1943 | + tty_unregister_driver(xr_usb_serial_tty_driver); |
---|
| 1944 | + put_tty_driver(xr_usb_serial_tty_driver); |
---|
| 1945 | +} |
---|
| 1946 | + |
---|
| 1947 | +module_init(xr_usb_serial_init); |
---|
| 1948 | +module_exit(xr_usb_serial_exit); |
---|
| 1949 | + |
---|
| 1950 | +MODULE_AUTHOR(DRIVER_AUTHOR); |
---|
| 1951 | +MODULE_DESCRIPTION(DRIVER_DESC); |
---|
| 1952 | +MODULE_LICENSE("GPL"); |
---|
| 1953 | +MODULE_ALIAS_CHARDEV_MAJOR(XR_USB_SERIAL_TTY_MAJOR); |
---|