Hi,
I'm sending the patch again, I have applied the modifications suggested by Randy
Dunlap. I hope this time the patch gets to you exactly as I have sended it.
I'm sending this patch using a different account, not gmail, becuase it is 
getting
my crazy, as it is changing a lot what I send. This time I have firstly send to 
me
and email, and applied the patch recived correctly, so I suppose it will get 
into
the mailing list correctly.

Here is a brief description of the device to see how the driver works:
The device works as an standard CDC device, it has 2 interfaces, the first one 
is
for firmware access and the second is the serial one. 
The device simply need some stuff to understand data comming from the usb 
buffer:
The First and Second byte is used for a Header, the Third and Fourth tells the 
device the amount of information the package holds.
Packages are 60 bytes long + Header Stuff.
I have reached a top of 300 bytes per transfer, which I think is being limited 
by
the hardware itself, I do not think it is actually a driver matter any more.

The driver registers himself with the USB-serial core and the USB Core.
I had to implement a probe function agains USB-serial, because other way, the
driver was attaching himself to both interfaces. I have tryed with different
configurations of usb_serial_driver with out exit, only the probe function could
handle this correctly.

Regards,
Naranjo Manuel Francisco

Signed-off-by: Naranjo, Manuel Francisco <[EMAIL PROTECTED]>

diff -uprN -X linux-vanilla/Documentation/dontdiff 
linux-vanilla/drivers/usb/serial/aircable.c linux/drivers/usb/serial/aircable.c
--- linux-vanilla/drivers/usb/serial/aircable.c 1969-12-31 21:00:00.000000000 
-0300
+++ linux/drivers/usb/serial/aircable.c 2006-07-10 14:03:31.000000000 -0300
@@ -0,0 +1,312 @@
+/*
+ * AIRcable USB Bluetooth dondgle Driver.
+ *
+ * Copyright (C) 2006 Manuel Francisco Naranjo ([EMAIL PROTECTED])
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This driver uses the USB Serial Core driver, to make AIRcable USB
+ * dongles 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 works like an standard ACM but witj little
+ * changes, it sends data in packages of 124 bytes, and adds at the begging 
+ * of each package 4 bytes for header. 
+ *
+ * I have also taken some info from a Greg Kroah-Hartman article
+ * url: http://www.linuxjournal.com/article/6573
+ * And from Linux Device Driver Kit CD, which is a great work, the authors 
+ * taken the work to recopile lots of information an knowladge in drivers
+ * development and made it all avaible inside a cd.
+ * URL: http://kernel.org/pub/linux/kernel/people/gregkh/ddk/
+ *
+ */
+
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+static int debug;
+
+#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
+#define HCI_COMPLETE_FRAME     64
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0b4"
+#define DRIVER_AUTHOR "Naranjo, Manuel Francisco <[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);
+
+
+static int aircable_probe(struct usb_serial *serial, const 
+                                               struct usb_device_id *id);
+static int aircable_write(struct usb_serial_port *port, 
+                                       const unsigned char *buf, int count);
+static void aircable_read_bulk_callback(struct urb *urb, struct pt_regs *regs);
+static void aircable_write_bulk_callback(struct urb *urb, struct pt_regs 
*regs);
+
+static struct usb_serial_driver aircable_device = {
+       .description =          "AIRcableUSB",
+       .id_table =             id_table,
+       .num_ports =            1,
+       .probe=                 aircable_probe,
+       .write=                 aircable_write,
+       .write_bulk_callback=   aircable_write_bulk_callback,
+       .read_bulk_callback=    aircable_read_bulk_callback,
+};
+
+static struct usb_driver aircable_driver = {
+       .name =         "AIRcableUSB",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     id_table,
+};
+
+static 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)) {
+                       /* we found a bulk out endpoint */
+                       dbg("found bulk out on endpoint %d", i);        
+       
+                       ++num_bulk_out;
+               }
+       }
+       if (num_bulk_out == 0) {
+               dbg("Invalid interface, discarding.\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int aircable_write(struct usb_serial_port *port, 
+                                       const unsigned char *source, int count)
+{
+       struct usb_serial *serial = port->serial;
+       struct urb *urb;
+       unsigned char *buffer;
+       int result;
+       int no_headers;
+       int payload_length;
+       int length;
+       int i;
+       int offset;
+       int src_offset;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       if (count == 0) {
+               dbg("%s - write request of 0 bytes", __FUNCTION__);
+               return 0;
+       }
+
+       spin_lock(&port->lock);
+               if (port->write_urb_busy) {
+                       spin_unlock(&port->lock);
+                       dbg("%s - already writing", __FUNCTION__);
+                       return 0;
+               }
+       port->write_urb_busy = 1;
+       spin_unlock(&port->lock);
+
+       no_headers = (count / MAX_HCI_FRAMESIZE) + 1;
+       payload_length = count;
+       buffer = kzalloc(count + no_headers * HCI_HEADER_LENGTH ,GFP_ATOMIC);
+       if (!buffer) {
+               err("%s ran out of kernel memory for urb ...", __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb) {
+               err("%s - no more free urbs", __FUNCTION__);
+               kfree (buffer);
+               return -ENOMEM;
+       }
+
+       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 * HCI_COMPLETE_FRAME;
+               src_offset = i * MAX_HCI_FRAMESIZE;
+               buffer[offset] = HCI_HEADER_0;
+               buffer[offset+1] = HCI_HEADER_1;
+               buffer[offset+2] = (unsigned char) length;
+               buffer[offset+3] = (unsigned char)(length >> 8);
+               memcpy(buffer + offset + HCI_HEADER_LENGTH, source + src_offset,
+                               length);
+       }
+               
+       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, length +
+                                               HCI_HEADER_LENGTH , buffer);
+       usb_fill_bulk_urb(urb, serial->dev,
+               usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+               buffer, count + no_headers * HCI_HEADER_LENGTH ,
+               aircable_write_bulk_callback, port);
+
+       port->write_urb_busy = 1;
+       result = usb_submit_urb(urb, GFP_ATOMIC);
+       if (result) {
+               dev_err(&port->dev, "%s - failed submitting write urb, error 
%d\n"
+                                                       ,__FUNCTION__, result);
+               kfree(buffer);
+               count = result;
+       }
+
+       usb_free_urb(urb);
+       dbg("%s write returning: %d", __FUNCTION__, count);
+
+       return count;
+}
+
+static void aircable_write_bulk_callback (struct urb *urb, struct pt_regs 
*regs)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+
+       /* free up the transfer buffer, as usb_free_urb() does not do this */
+       kfree(urb->transfer_buffer);
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       port->write_urb_busy = 1;
+       if (urb->status) {
+               dbg("nonzero write bulk status received: %d", urb->status);
+               return;
+       }
+       usb_serial_port_softint((void *)port);
+       schedule_work(&port->work);
+}
+
+static 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;
+       }
+       
+       tty = port->tty;        
+       if (tty && urb->actual_length) {
+               usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+                               urb->actual_length , urb->transfer_buffer);
+               if (urb->actual_length > HCI_HEADER_LENGTH){
+                       remaining = urb->actual_length;
+                       no_packages = urb->actual_length / (HCI_COMPLETE_FRAME);
+                       if (urb->actual_length % HCI_COMPLETE_FRAME != 0)
+                               no_packages+=1;
+                       for (i = 0; i < no_packages ; ++i) {
+                               if (remaining > (HCI_COMPLETE_FRAME))
+                                       package_length = HCI_COMPLETE_FRAME;
+                               else
+                                       package_length = remaining;
+                               remaining -= package_length;
+                               data = kmalloc(package_length - 
+                                               HCI_HEADER_LENGTH, GFP_ATOMIC);
+                               if (!data){
+                                       err("%s ran out of kernel memory for 
urb ...", 
+                                                               __FUNCTION__);
+                                       return -ENOMEM;
+                               }
+
+                               memcpy(data, urb->transfer_buffer +
+                                       HCI_HEADER_LENGTH +
+                                       (HCI_COMPLETE_FRAME) * (i),
+                                       package_length - HCI_HEADER_LENGTH);
+                               tty_buffer_request_room(tty,package_length -
+                                                       HCI_HEADER_LENGTH);
+                               tty_insert_flip_string(tty,data,
+                                       package_length - HCI_HEADER_LENGTH);
+                               tty_flip_buffer_push(tty);
+                               kfree(data);    
+                       }
+               }
+       }
+       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);
+}
+
+static int __init aircable_init (void)
+{
+       int retval;
+       retval = usb_serial_register(&aircable_device);         
+       if (retval)
+               goto failed_serial_register;
+       retval = usb_register(&aircable_driver);
+       if (retval) 
+               goto failed_usb_register;
+       return 0;
+
+failed_serial_register:
+       usb_serial_deregister(&aircable_device);
+failed_usb_register:
+       return retval;  
+}
+
+static void __exit aircable_exit (void)
+{
+       usb_deregister(&aircable_driver);
+       usb_serial_deregister(&aircable_device);        
+}
+
+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 linux-vanilla/Documentation/dontdiff 
linux-vanilla/drivers/usb/serial/Kconfig linux/drivers/usb/serial/Kconfig
--- linux-vanilla/drivers/usb/serial/Kconfig    2006-03-20 02:53:29.000000000 
-0300
+++ linux/drivers/usb/serial/Kconfig    2006-07-10 13:33:18.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.
+
 config USB_EZUSB
        bool
        depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || 
USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT
diff -uprN -X linux-vanilla/Documentation/dontdiff 
linux-vanilla/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile
--- linux-vanilla/drivers/usb/serial/Makefile   2006-03-20 02:53:29.000000000 
-0300
+++ linux/drivers/usb/serial/Makefile   2006-07-08 15:09:54.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.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
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to