1*5fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 23fe70ba2SManuel Francisco Naranjo /* 33fe70ba2SManuel Francisco Naranjo * AIRcable USB Bluetooth Dongle Driver. 43fe70ba2SManuel Francisco Naranjo * 54272568bSJohan Hovold * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com> 63fe70ba2SManuel Francisco Naranjo * Copyright (C) 2006 Manuel Francisco Naranjo (naranjo.manuel@gmail.com) 74272568bSJohan Hovold * 83fe70ba2SManuel Francisco Naranjo * This program is free software; you can redistribute it and/or modify it under 93fe70ba2SManuel Francisco Naranjo * the terms of the GNU General Public License version 2 as published by the 103fe70ba2SManuel Francisco Naranjo * Free Software Foundation. 113fe70ba2SManuel Francisco Naranjo * 123fe70ba2SManuel Francisco Naranjo * The device works as an standard CDC device, it has 2 interfaces, the first 133fe70ba2SManuel Francisco Naranjo * one is for firmware access and the second is the serial one. 14cd8c5053SRahul Bedarkar * The protocol is very simply, there are two possibilities reading or writing. 15beb7dd86SRobert P. J. Day * When writing the first urb must have a Header that starts with 0x20 0x29 the 16cd8c5053SRahul Bedarkar * next two bytes must say how much data will be sent. 173fe70ba2SManuel Francisco Naranjo * When reading the process is almost equal except that the header starts with 183fe70ba2SManuel Francisco Naranjo * 0x00 0x20. 193fe70ba2SManuel Francisco Naranjo * 2025985edcSLucas De Marchi * The device simply need some stuff to understand data coming from the usb 213fe70ba2SManuel Francisco Naranjo * buffer: The First and Second byte is used for a Header, the Third and Fourth 223fe70ba2SManuel Francisco Naranjo * tells the device the amount of information the package holds. 233fe70ba2SManuel Francisco Naranjo * Packages are 60 bytes long Header Stuff. 24beb7dd86SRobert P. J. Day * When writing to the device the first two bytes of the header are 0x20 0x29 253fe70ba2SManuel Francisco Naranjo * When reading the bytes are 0x00 0x20, or 0x00 0x10, there is an strange 263fe70ba2SManuel Francisco Naranjo * situation, when too much data arrives to the device because it sends the data 273fe70ba2SManuel Francisco Naranjo * but with out the header. I will use a simply hack to override this situation, 283fe70ba2SManuel Francisco Naranjo * if there is data coming that does not contain any header, then that is data 293fe70ba2SManuel Francisco Naranjo * that must go directly to the tty, as there is no documentation about if there 303fe70ba2SManuel Francisco Naranjo * is any other control code, I will simply check for the first 313fe70ba2SManuel Francisco Naranjo * one. 323fe70ba2SManuel Francisco Naranjo * 333fe70ba2SManuel Francisco Naranjo * I have taken some info from a Greg Kroah-Hartman article: 343fe70ba2SManuel Francisco Naranjo * http://www.linuxjournal.com/article/6573 353fe70ba2SManuel Francisco Naranjo * And from Linux Device Driver Kit CD, which is a great work, the authors taken 36cd8c5053SRahul Bedarkar * the work to recompile lots of information an knowledge in drivers development 37cd8c5053SRahul Bedarkar * and made it all available inside a cd. 383fe70ba2SManuel Francisco Naranjo * URL: http://kernel.org/pub/linux/kernel/people/gregkh/ddk/ 393fe70ba2SManuel Francisco Naranjo * 403fe70ba2SManuel Francisco Naranjo */ 413fe70ba2SManuel Francisco Naranjo 424272568bSJohan Hovold #include <asm/unaligned.h> 433fe70ba2SManuel Francisco Naranjo #include <linux/tty.h> 445a0e3ad6STejun Heo #include <linux/slab.h> 456eb0de82SPaul Gortmaker #include <linux/module.h> 463fe70ba2SManuel Francisco Naranjo #include <linux/tty_flip.h> 473fe70ba2SManuel Francisco Naranjo #include <linux/usb.h> 483fe70ba2SManuel Francisco Naranjo #include <linux/usb/serial.h> 493fe70ba2SManuel Francisco Naranjo 503fe70ba2SManuel Francisco Naranjo /* Vendor and Product ID */ 513fe70ba2SManuel Francisco Naranjo #define AIRCABLE_VID 0x16CA 523fe70ba2SManuel Francisco Naranjo #define AIRCABLE_USB_PID 0x1502 533fe70ba2SManuel Francisco Naranjo 543fe70ba2SManuel Francisco Naranjo /* Protocol Stuff */ 553fe70ba2SManuel Francisco Naranjo #define HCI_HEADER_LENGTH 0x4 563fe70ba2SManuel Francisco Naranjo #define TX_HEADER_0 0x20 573fe70ba2SManuel Francisco Naranjo #define TX_HEADER_1 0x29 583fe70ba2SManuel Francisco Naranjo #define RX_HEADER_0 0x00 593fe70ba2SManuel Francisco Naranjo #define RX_HEADER_1 0x20 603fe70ba2SManuel Francisco Naranjo #define HCI_COMPLETE_FRAME 64 613fe70ba2SManuel Francisco Naranjo 623fe70ba2SManuel Francisco Naranjo /* rx_flags */ 633fe70ba2SManuel Francisco Naranjo #define THROTTLED 0x01 643fe70ba2SManuel Francisco Naranjo #define ACTUALLY_THROTTLED 0x02 653fe70ba2SManuel Francisco Naranjo 664272568bSJohan Hovold #define DRIVER_AUTHOR "Naranjo, Manuel Francisco <naranjo.manuel@gmail.com>, Johan Hovold <jhovold@gmail.com>" 673fe70ba2SManuel Francisco Naranjo #define DRIVER_DESC "AIRcable USB Driver" 683fe70ba2SManuel Francisco Naranjo 693fe70ba2SManuel Francisco Naranjo /* ID table that will be registered with USB core */ 707d40d7e8SNémeth Márton static const struct usb_device_id id_table[] = { 713fe70ba2SManuel Francisco Naranjo { USB_DEVICE(AIRCABLE_VID, AIRCABLE_USB_PID) }, 723fe70ba2SManuel Francisco Naranjo { }, 733fe70ba2SManuel Francisco Naranjo }; 743fe70ba2SManuel Francisco Naranjo MODULE_DEVICE_TABLE(usb, id_table); 753fe70ba2SManuel Francisco Naranjo 764272568bSJohan Hovold static int aircable_prepare_write_buffer(struct usb_serial_port *port, 77c23e5fc1SJohan Hovold void *dest, size_t size) 783fe70ba2SManuel Francisco Naranjo { 79c23e5fc1SJohan Hovold int count; 80c23e5fc1SJohan Hovold unsigned char *buf = dest; 813fe70ba2SManuel Francisco Naranjo 824272568bSJohan Hovold count = kfifo_out_locked(&port->write_fifo, buf + HCI_HEADER_LENGTH, 834272568bSJohan Hovold size - HCI_HEADER_LENGTH, &port->lock); 843fe70ba2SManuel Francisco Naranjo buf[0] = TX_HEADER_0; 853fe70ba2SManuel Francisco Naranjo buf[1] = TX_HEADER_1; 864272568bSJohan Hovold put_unaligned_le16(count, &buf[2]); 873fe70ba2SManuel Francisco Naranjo 88f26c2889SJohan Hovold return count + HCI_HEADER_LENGTH; 893fe70ba2SManuel Francisco Naranjo } 903fe70ba2SManuel Francisco Naranjo 915f391979SJohan Hovold static int aircable_calc_num_ports(struct usb_serial *serial, 925f391979SJohan Hovold struct usb_serial_endpoints *epds) 933fe70ba2SManuel Francisco Naranjo { 945f391979SJohan Hovold /* Ignore the first interface, which has no bulk endpoints. */ 955f391979SJohan Hovold if (epds->num_bulk_out == 0) { 965f391979SJohan Hovold dev_dbg(&serial->interface->dev, 975f391979SJohan Hovold "ignoring interface with no bulk-out endpoints\n"); 983fe70ba2SManuel Francisco Naranjo return -ENODEV; 993fe70ba2SManuel Francisco Naranjo } 1003fe70ba2SManuel Francisco Naranjo 1015f391979SJohan Hovold return 1; 1023fe70ba2SManuel Francisco Naranjo } 1033fe70ba2SManuel Francisco Naranjo 10405c7cd39SJiri Slaby static int aircable_process_packet(struct usb_serial_port *port, 10505c7cd39SJiri Slaby int has_headers, char *packet, int len) 1063fe70ba2SManuel Francisco Naranjo { 1074272568bSJohan Hovold if (has_headers) { 1084272568bSJohan Hovold len -= HCI_HEADER_LENGTH; 1094272568bSJohan Hovold packet += HCI_HEADER_LENGTH; 1103fe70ba2SManuel Francisco Naranjo } 1114272568bSJohan Hovold if (len <= 0) { 11266afb5b5SGreg Kroah-Hartman dev_dbg(&port->dev, "%s - malformed packet\n", __func__); 1133fe70ba2SManuel Francisco Naranjo return 0; 1143fe70ba2SManuel Francisco Naranjo } 1153fe70ba2SManuel Francisco Naranjo 11605c7cd39SJiri Slaby tty_insert_flip_string(&port->port, packet, len); 1173fe70ba2SManuel Francisco Naranjo 1184272568bSJohan Hovold return len; 1193fe70ba2SManuel Francisco Naranjo } 1203fe70ba2SManuel Francisco Naranjo 1214272568bSJohan Hovold static void aircable_process_read_urb(struct urb *urb) 1223fe70ba2SManuel Francisco Naranjo { 1233fe70ba2SManuel Francisco Naranjo struct usb_serial_port *port = urb->context; 1244272568bSJohan Hovold char *data = (char *)urb->transfer_buffer; 1254272568bSJohan Hovold int has_headers; 1264272568bSJohan Hovold int count; 1274272568bSJohan Hovold int len; 1284272568bSJohan Hovold int i; 1293fe70ba2SManuel Francisco Naranjo 1304272568bSJohan Hovold has_headers = (urb->actual_length > 2 && data[0] == RX_HEADER_0); 1313fe70ba2SManuel Francisco Naranjo 1324272568bSJohan Hovold count = 0; 1334272568bSJohan Hovold for (i = 0; i < urb->actual_length; i += HCI_COMPLETE_FRAME) { 1344272568bSJohan Hovold len = min_t(int, urb->actual_length - i, HCI_COMPLETE_FRAME); 13505c7cd39SJiri Slaby count += aircable_process_packet(port, has_headers, 1364272568bSJohan Hovold &data[i], len); 1373fe70ba2SManuel Francisco Naranjo } 1384272568bSJohan Hovold 1394272568bSJohan Hovold if (count) 1402e124b4aSJiri Slaby tty_flip_buffer_push(&port->port); 1413fe70ba2SManuel Francisco Naranjo } 1423fe70ba2SManuel Francisco Naranjo 1433fe70ba2SManuel Francisco Naranjo static struct usb_serial_driver aircable_device = { 14452d67f0bSJohannes Hölzl .driver = { 14552d67f0bSJohannes Hölzl .owner = THIS_MODULE, 14652d67f0bSJohannes Hölzl .name = "aircable", 14752d67f0bSJohannes Hölzl }, 1483fe70ba2SManuel Francisco Naranjo .id_table = id_table, 1494272568bSJohan Hovold .bulk_out_size = HCI_COMPLETE_FRAME, 1505f391979SJohan Hovold .calc_num_ports = aircable_calc_num_ports, 1514272568bSJohan Hovold .process_read_urb = aircable_process_read_urb, 1524272568bSJohan Hovold .prepare_write_buffer = aircable_prepare_write_buffer, 1534272568bSJohan Hovold .throttle = usb_serial_generic_throttle, 1544272568bSJohan Hovold .unthrottle = usb_serial_generic_unthrottle, 1553fe70ba2SManuel Francisco Naranjo }; 1563fe70ba2SManuel Francisco Naranjo 15708a4f6bcSAlan Stern static struct usb_serial_driver * const serial_drivers[] = { 15808a4f6bcSAlan Stern &aircable_device, NULL 15908a4f6bcSAlan Stern }; 16008a4f6bcSAlan Stern 16168e24113SGreg Kroah-Hartman module_usb_serial_driver(serial_drivers, id_table); 1623fe70ba2SManuel Francisco Naranjo 1633fe70ba2SManuel Francisco Naranjo MODULE_AUTHOR(DRIVER_AUTHOR); 1643fe70ba2SManuel Francisco Naranjo MODULE_DESCRIPTION(DRIVER_DESC); 1653fe70ba2SManuel Francisco Naranjo MODULE_LICENSE("GPL"); 166