Hi:
I have sended this before, but i think the driver patch could be lost 
between the huge amount of emails this list receives every day.
This driver is for using AIRcable USB Bluetooth Dongles able to work on 
Linux. This driver does not belong to the Bluetooth part of the kernel, 
because the hole Bluetooth stack is implemented inside the device firmware.
The AIRcable USB protocol is like the usbserial protocol, except that it 
makes some changes. The first and second bytes are used for the protocol 
header, the third and fourth bytes are the size of the package sended. 
Data must be sended in 60 bytes packages (Including Header), more than 
64 bits makes the device firmware panic and reboots it self.
The driver is actually working when ever the data transaction is less 
than 180 bytes (with out the header). I do not know if it is an 
implementation problem of the driver, or either a problem in the 
hardware. I have attached two devices to my pc and make some tests, if 
data transfer were less than 180 bytes everything worked all right, but 
if there was a transaction of over 180 bytes the sending device panic.
I have thought about putting the sending data to the BULK OUT inside a 
interation, but the driver crashed when data there was data in the BULK IN.
I do not know if 180 bytes limit is something bad at all, I'm going to 
test OBEX in a couple of days, I think that OBEX could be a good testing 
point because of the amount of data it transfers.
I'm wide open to correction, this is my first try with drivers, I have 
done my best to avoid flaws, I have based my driver on the code inside 
usbserial.c and generic.c.


Regards,
Manuel Naranjo


Here is the patch:

diff -uprN -X Documentation/dontdiff 
a/drivers/usb/serial/AIRcable-USB-serial.c 
b/drivers/usb/serial/AIRcable-USB-serial.c
--- a/drivers/usb/serial/AIRcable-USB-serial.c  1969-12-31 
21:00:00.000000000 -0300
+++ b/drivers/usb/serial/AIRcable-USB-serial.c  2006-07-04 
09:34:10.000000000 -0300
@@ -0,0 +1,309 @@
+/*
+ * AIRcable USB Bluetooth dondgle Driver.
+ *
+ * This driver is a modified version of USB Serial Converter driver,
+ * that lets AIRcable devices work.
+ *
+ * The AIRcable USB Bluetooth Dongles has two interfaces, the first
+ * one is usless for serial working, I think it must be for firmware
+ * updating.
+ * The second interfaces has a bulk in and a bulk out, and is the one
+ * used for serial transactions.
+ * AIRcable USB Bluetooth Dongles uses a modified version of the 
+ * standard USB serial generic protocol, it sends data in packages of 
  + * 64 bytes, and adds at the begging of each package 4 bytes for
+ * header. See AIRcable-USB-serial.h for Header Information.
+ *
+ *
+ * I have also taken some info from a Greg Kroah-Hartman article
+ *     url: http://www.linuxjournal.com/article/6573
+ *
+ * Copyright (C) 2006
+ *         Manuel Francisco Naranjo ([EMAIL PROTECTED])
+ *
+ * License: GNU/GPL v2 or newer.
+ *
+ * (03/07/2006) manuelnaranjo
+ *     Trying to fix a bug, if more than 1 dongle is connected to the
+ *     computer and there are transfers of more than 180 bytes (without
+ *     including the Header) the driver crashes.
+ *
+ * (23/06/2006) manuelnaranjo
+ *     v0.1 Started
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <../drivers/usb/serial/usb-serial.h>
+#include "AIRcable-USB-serial.h"
+
+
+static int debug;
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0b2"
+#define DRIVER_AUTHOR "Naranjo, Manuel Francisco. email: 
[EMAIL PROTECTED]"
+#define DRIVER_DESC "AIRcable USB Driver"
+
+
+/* ID table that will be registered with USB core */
+static struct usb_device_id id_table [] = {
+        { USB_DEVICE(AIRCABLE_VID, AIRCABLE_USB_PID) },
+        { },
+};
+MODULE_DEVICE_TABLE (usb, id_table);
+
+
+
+/* Methods declaration */
+int aircable_probe (struct usb_serial *serial, const struct 
         +                                                   usb_device_id *id);
+int aircable_write(struct usb_serial_port *port, const unsigned 
char    +                                               *buf, int count);
+void aircable_read_bulk_callback(struct urb *urb, 
struct pt_regs          +                                                       
        *regs);
+
+/* All device info needed for AIRcable USB device */
+static struct usb_serial_device_type aircable_device = {
+    .owner =                   THIS_MODULE,
+    .name =                    "AIRcable USB serial (device)",
+    .short_name =              "aircable_device",
+    .id_table =                id_table,
+    .num_ports =               1,
+    .probe=                    aircable_probe,
+    .write=                    aircable_write,
+    .read_bulk_callback=       aircable_read_bulk_callback,
+};
+
+static struct usb_driver aircable_driver = {
+       .name =         "AIRcable USB serial (driver)",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     id_table,
+};
+
+/* Methods implementation */
+
+/* Based on serial_probe */
+int aircable_probe (struct usb_serial *serial, const struct            +       
                                 
usb_device_id *id)
+{
+       struct usb_host_interface *iface_desc =                         +       
         
serial->interface->cur_altsetting;
+       struct usb_endpoint_descriptor *endpoint;
+       int num_bulk_out=0;
+
+       int i;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+       
+               if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+                   ((endpoint->bmAttributes & 3) == 0x02)) {
+                       dbg("found bulk out on endpoint %d", i);                
        
+                       ++num_bulk_out;
+               }
+       }
+
+       if (num_bulk_out == 0) {
+               dbg("Invalid interface, discarding.\n");
+               return -5;
+       }
+       return 0;
+}
+
+
+
+/*
+ * Based on Generic_write and AIRcable Windows driver
+ * Thanks Juergen Kienhoefer from AIRcable for the support, and
+ * giving me access to their Windows Driver.
+ */
+int aircable_write(struct usb_serial_port *port, const unsigned char 
*pSrcBuf, int count)
+{
+       struct usb_serial *serial = port->serial;
+       unsigned char *pBuf;    
+       int result;
+       unsigned long no_headers;
+       unsigned long payload_length;
+       unsigned long length;
+       unsigned long i;
+       unsigned long offset;   
+       unsigned long src_offset;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       if (count == 0) {
+               dbg("%s - write request of 0 bytes", __FUNCTION__);
+               return (0);
+       }
+
+       /* only do something if we have a bulk out endpoint */
+       if (serial->num_bulk_out) {
+               if (port->write_urb->status == -EINPROGRESS) {
+                       dbg("%s - already writing", __FUNCTION__);
+                       return (0);
+               }
+               
+               dbg("Writting: %s", pSrcBuf);
+
+               no_headers = (count / MAX_HCI_FRAMESIZE) + 1;
+
+               pBuf = kmalloc(count + (no_headers *HCI_HEADER_LENGTH) , +      
                                         
GFP_KERNEL);
+               memset (pBuf, 0, count + (no_headers *HCI_HEADER_LENGTH +       
                                                        ));
+
+               payload_length = count;
+               length = 0;
+
+               for(i = 0; i < no_headers; i++) {
+                       if(payload_length >= MAX_HCI_FRAMESIZE)
+                               length = MAX_HCI_FRAMESIZE;
+                       else
+                               length = payload_length;
+                       payload_length -= length;
+
+                       offset = i * COMPLETE_PACKAGE;
+                       src_offset = i * MAX_HCI_FRAMESIZE;
+                       pBuf[offset] = HCI_HEADER_0;
+                       pBuf[offset+1] = HCI_HEADER_1;
+                       pBuf[offset+2] = (unsigned char) length;
+                       pBuf[offset+3] = (unsigned char)(length >> 8);
+
+                       memcpy(pBuf + offset + HCI_HEADER_LENGTH,       +       
                                pSrcBuf + 
src_offset, length);
+               }
+
+               port->write_urb->transfer_buffer = pBuf;
+               
+               /* set up our urb */
+               usb_fill_bulk_urb (port->write_urb, serial->dev,
+                                  usb_sndbulkpipe (serial->dev,        +       
                         
port->bulk_out_endpointAddress),
+                                  port->write_urb->transfer_buffer,    +       
                                (count + 
(no_headers             +                                               
*HCI_HEADER_LENGTH )),
+                                  serial->type->write_bulk_callback,   +       
                                                        port);
+
+               /* send the data out the bulk port */
+               result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+
+               if (result)
+                       dev_err(&port->dev,                             +       
                 "%s - failed submitting write urb, 
error %d\n", +                          __FUNCTION__, result);
+               else
+                       result = count;
+
+               return result;
+
+               kfree(pBuf);
+       }
+
+       /* no bulk out, so return 0 bytes written */
+       return (0);
+}
+
+/*
+ * This internal function simply drops the Header on every read,
+ * It must only recive complete packages.
+ */
+void aircable_parse_read(struct tty_struct *tty, unsigned 
char *data,     +                                                            
int lenght)
+{
+       int i;          
+       if ( lenght > HCI_HEADER_LENGTH) {
+               for (i = HCI_HEADER_LENGTH; i < lenght; i++) {
+/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+                       if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               tty_flip_buffer_push(tty);
+                       }
+                       
+       /* this doesn't actually push the data through
+       unless tty->low_latency is set */
+                       tty_insert_flip_char(tty, data[i], 0);
+               }       
+       }
+}
+
+void aircable_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_serial_port *port = (struct usb_serial_port  
+                                                       *)urb->context;
+       struct usb_serial *serial = port->serial;
+       struct tty_struct *tty;
+       unsigned char *data;
+       unsigned long no_packages;
+       unsigned long remaining, package_length;        
+       unsigned long i;
+       int result;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       if (urb->status) {
+               dbg("%s - nonzero read bulk status received: %d",
+                                       __FUNCTION__, urb->status);
+               return;
+       }
+       
+       usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+                       urb->actual_length, urb->transfer_buffer);
+
+       tty = port->tty;        
+       if (tty && urb->actual_length) {                
+       //Does this package includes more information than the header???
+               if (urb->actual_length > HCI_HEADER_LENGTH) {
+                       remaining = urb->actual_length;
+
+                       no_packages = (urb->actual_length /
+                                               COMPLETE_PACKAGE )+1;
+                       
+                       for (i = 0; i < no_packages ; ++i) {
+                               if (remaining > COMPLETE_PACKAGE)               
+               
+                                    package_length =  COMPLETE_PACKAGE;
+                               else
+                                    package_length = remaining;                
+               
+
+                               remaining -= package_length;                    
+       
+
+                               data = kmalloc(package_length,
+                                                       GFP_KERNEL);
+
+                               memset (data, 0, package_length);
+                               memcpy(data, urb->transfer_buffer +
+                                       COMPLETE_PACKAGE * i,
+                                       package_length);
+                               aircable_parse_read(tty, data,
+                                               package_length);
+                               
+                               kfree(data);
+                       }
+                       tty_flip_buffer_push(tty);
+               }
+       }
+       
+       /* Continue trying to always read  */
+       usb_fill_bulk_urb (port->read_urb, serial->dev,
+                       usb_rcvbulkpipe (serial->dev,
+                                       port->bulk_in_endpointAddress),
+                       port->read_urb->transfer_buffer,
+                       port->read_urb->transfer_buffer_length,
+                       serial->type->read_bulk_callback, port);
+       result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+       if (result)
+               dev_err(&port->dev,
+                       "%s - failed resubmitting read urb, error %d\n",
+                       __FUNCTION__, result);
+}
+
+/* END OF Methods Implementatio */
+
+static int __init aircable_init (void)
+{
+       usb_serial_register (&aircable_device); 
+       usb_register (&aircable_driver);
+       return 0;
+}
+
+static void __exit aircable_exit (void)
+{
+       usb_deregister (&aircable_driver);
+       usb_serial_deregister (&aircable_device);       
+}
+
+/* Module information */
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_VERSION( DRIVER_VERSION );
+MODULE_LICENSE("GPL");
+
+
+module_init(aircable_init);
+module_exit(aircable_exit);
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff -uprN -X Documentation/dontdiff 
a/drivers/usb/serial/AIRcable-USB-serial.h 
b/drivers/usb/serial/AIRcable-USB-serial.h
--- a/drivers/usb/serial/AIRcable-USB-serial.h  1969-12-31 
21:00:00.000000000 -0300
+++ b/drivers/usb/serial/AIRcable-USB-serial.h  2006-07-04 
09:34:53.000000000 -0300
@@ -0,0 +1,33 @@
+/* AIRcable USB Bluetooth dondgle Driver.
+ *
+ * This driver is a modified version of USB Serial Converter driver,
+ * that lets AIRcable devices work.
+ *
+ * Copyright (C) 2006
+ *         Manuel Francisco Naranjo ([EMAIL PROTECTED])
+ *
+ * License: GNU/GPL v2 or newer.
+ *
+ */
+
+
+#ifndef __AIRCABLE_USB_LINUX_H
+#define __AIRCABLE_USB_LINUX_H
+
+#define AIRCABLE_VID           0x16CA  /* Vendor Id */
+#define AIRCABLE_USB_PID       0x1502  /* Product Id */
+
+/* The following defintions are required to Add/Strip HCI headers from 
+   URB sent over bulk endpoints */
+#define HCI_HEADER_LENGTH      (0x4)
+#define HCI_HEADER_0           (0x20)
+#define HCI_HEADER_1           (0x29)
+#define MAX_HCI_FRAMESIZE      (60) //124 252 956
+#define COMPLETE_PACKAGE       HCI_HEADER_LENGTH + MAX_HCI_FRAMESIZE
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg(format, arg...) if (debug) do { printk(KERN_DEBUG "%s: " 
format "\n" , __FILE__ , ## arg); } while (0)
+#endif 
+/* ifdef __LINUX_USB_SERIAL_H */
+
+
diff -uprN -X Documentation/dontdiff a/drivers/usb/serial/Kconfig 
b/drivers/usb/serial/Kconfig
--- a/drivers/usb/serial/Kconfig        2006-03-20 02:53:29.000000000 -0300
+++ b/drivers/usb/serial/Kconfig        2006-07-04 09:37:38.000000000 -0300
@@ -484,6 +484,15 @@ config USB_SERIAL_OMNINET
          To compile this driver as a module, choose M here: the
          module will be called omninet.

+config USB_SERIAL_AIRCABLE
+       tristate "AIRcable USB Bluetooth dongle Driver (EXPERIMENTAL)"
+       depends on USB_SERIAL && EXPERIMENTAL
+       help
+         Say Y here if you want to use an AIRcable USB Bluetooth
+         dongle.
+         To compile this driver as a module, choose M here: the
+         module will be called AIRcable-USB-serial.
+
  config USB_EZUSB
        bool
        depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || 
USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT
diff -uprN -X Documentation/dontdiff a/drivers/usb/serial/Makefile 
b/drivers/usb/serial/Makefile
--- a/drivers/usb/serial/Makefile       2006-03-20 02:53:29.000000000 -0300
+++ b/drivers/usb/serial/Makefile       2006-07-04 09:38:29.000000000 -0300
@@ -40,4 +40,5 @@ obj-$(CONFIG_USB_SERIAL_TI)                   += ti_usb_
  obj-$(CONFIG_USB_SERIAL_VISOR)                        += visor.o
  obj-$(CONFIG_USB_SERIAL_WHITEHEAT)            += whiteheat.o
  obj-$(CONFIG_USB_SERIAL_XIRCOM)                       += keyspan_pda.o
+obj-$(CONFIG_USB_SERIAL_AIRCABLE)              += AIRcable-USB-serial.o



Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to