Return-Path: Message-ID: Date: Tue, 24 Apr 2007 16:43:10 +0530 From: "list subscribe" To: "BlueZ development" MIME-Version: 1.0 Subject: [Bluez-devel] [PATCH]Dynamic Alternate Setting patch (hci_usb.c) Reply-To: BlueZ development List-Id: BlueZ development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: multipart/mixed; boundary="===============0429618246==" Sender: bluez-devel-bounces@lists.sourceforge.net Errors-To: bluez-devel-bounces@lists.sourceforge.net --===============0429618246== Content-Type: multipart/alternative; boundary="----=_Part_19967_6038016.1177413190756" ------=_Part_19967_6038016.1177413190756 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline Hi, As per the discussion on #bluez channel , I am attaching a patch which dynamically manages the the alternate settings for SCO channels. The patch includes the following : 1. It declares a work queue(config_work), which is scheduled when 1. There is a change in number of SCO channels OR 2. There is a change in the Voice setting. 2. On invocation it determines the alternate setting based on the table given in HCI - usb spec docs. The table is also mentioned in the patch. 3. It then empties all the queued isochronous URBs , except those which are already submitted. 4. It then sets the alternate setting by calling usb_set_interface(). I have tested this patch using "scotest". I am using 2.6.21-rc7 with sco-flowcontrol-v4.2.diff patch. Let me know if any changes are necessary. Any suggestions are welcome. Alok. --- hci_usb.c.orig 2007-04-16 19:37:41.000000000 +0530 +++ hci_usb.c 2007-04-24 01:41:31.000000000 +0530 @@ -47,6 +47,8 @@ #include +#include + #include #include @@ -57,6 +59,21 @@ #define BT_DBG(D...) #endif +/* The number of SCO channels */ +int NoSco=0; +/* The Voice setting */ +__u16 VocSetting=0; +/* if bit=0,its 8bit encoding else its 16bit */ +__u16 bit = 0x20; + +struct hci_usb *hUSB; +struct usb_device *usbdevice; +struct usb_interface *isocIface; +/* The Workque Function */ +static void set_alternate_config(struct work_struct *work); +static DECLARE_WORK(config_work, set_alternate_config); + + #ifndef CONFIG_BT_HCIUSB_ZERO_PACKET #undef URB_ZERO_PACKET #define URB_ZERO_PACKET 0 @@ -840,6 +857,10 @@ static void hci_usb_notify(struct hci_dev *hdev, unsigned int evt) { BT_DBG("%s evt %d", hdev->name, evt); + NoSco = hdev->conn_hash.sco_num; + VocSetting = hdev->voice_setting; + hUSB = (struct hci_usb *) hdev->driver_data; + schedule_work(&config_work); } static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -854,7 +875,7 @@ struct hci_usb *husb; struct hci_dev *hdev; int i, e, size, isoc_ifnum, isoc_alts; - + usbdevice = interface_to_usbdev(intf); BT_DBG("udev %p intf %p", udev, intf); if (!id->driver_info) { @@ -926,9 +947,11 @@ isoc_ifnum = 1; #ifdef CONFIG_BT_HCIUSB_SCO - if (isoc && !(id->driver_info & (HCI_BROKEN_ISOC | HCI_SNIFFER))) + if (isoc && !(id->driver_info & (HCI_BROKEN_ISOC | HCI_SNIFFER))){ isoc_iface = usb_ifnum_to_if(udev, isoc_ifnum); - + isocIface = usb_ifnum_to_if(udev, isoc_ifnum); + } + if (isoc_iface) { int a; struct usb_host_endpoint *isoc_out_ep = NULL; @@ -1142,6 +1165,121 @@ return 0; } + +/*Set the alternate setting based on the number of SCO channels and the + voice setting.This function is invoked when there is a change in Number of + SCO channels or when the voice encoding changes.*/ +static void set_alternate_config(struct work_struct *work) +{ + int isocIfnum=1, isocAlt=0; + struct usb_host_endpoint *ep; + struct usb_host_interface *uif; + struct _urb *_urb,*_tmp; + struct _urb_queue *q = &hUSB->pending_q[isoc]; + unsigned long flags; + atomic_t temp;/*Holds the number of URBs we need to skip(which are submitted)*/ + struct list_head inprocess;/*This list holds the already submitted URBs */ + + /*Change the alternate setting only if the number of SCO channels are more than 1 */ + if(NoSco > 0){ + /* The alternate setting selection is based on the following table */ + /* No. of SCO channels Bit-Encoding Alternate Setting Max. Packet Size */ + /* 1 8bit 1 9 */ + /* 1 16bit 2 17 */ + /* 2 8bit 2 17 */ + /* 2 16bit 4 33 */ + /* 3 8bit 3 25 */ + /* 3 16bit 5 49 */ + switch(NoSco) + { + case 1: + if(VocSetting && bit) + isocAlt=2; + else + isocAlt=1; + break; + case 2: + if(VocSetting && bit) + isocAlt=4; + else + isocAlt=2; + break; + case 3: + if(VocSetting && bit) + isocAlt=5; + else + isocAlt=3; + break; + } + + /*Stop Current TX */ + clear_bit(HCI_USB_TX_WAKEUP, &hUSB->state); + INIT_LIST_HEAD(&inprocess); + temp = hUSB->pending_tx[isoc]; + /* We cannot purge URBs which have been submitted. inprocess is a */ + /* temporary list which holds the currently submitted URBs. */ + /* This list is later merged with the emptyed pending queue. */ + + while ((_urb = _urb_dequeue(q))) { + /*Dequeue all the submitted URBs and put them in the temporary list*/ + if(!atomic_dec_and_test(&temp)){ + _urb->queue = q; + list_add(&_urb->list, &inprocess); + } + else{ + /*Unlink all the rest of URBs and put them into the completed queue.*/ + _urb_unlink(_urb); + _urb_queue_tail(__completed_q(hUSB,HCI_SCODATA_PKT), _urb); + } + } + /*merge the inprocess queue with the pending queue*/ + spin_lock_irqsave(&q->lock, flags); + list_for_each_entry_safe(_urb, _tmp, &inprocess, list) { + list_move_tail(&_urb->list, &q->head); + } + spin_unlock_irqrestore(&q->lock, flags); + + /* Set the setting and the in/out endpoints */ + if (isocIface) { + int e; + struct usb_host_endpoint *out = NULL; + struct usb_host_endpoint *in = NULL; + uif = &isocIface->altsetting[isocAlt]; + for (e = 0; e < uif->desc.bNumEndpoints; e++) { + ep = &uif->endpoint[e]; + switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_ISOC: + if (ep->desc.bEndpointAddress & USB_DIR_IN) + in = ep; + else + out = ep; + break; + } + } + + if (!in || !out) + BT_DBG("Isoc endpoints not found"); + else { + BT_DBG("isoc ifnum %d alts %d", isocIfnum, isocAlt); + if (usb_set_interface(usbdevice, isocIfnum, isocAlt)) { + BT_ERR("Can't set isoc interface settings"); + hUSB->isoc_iface = isocIface; + usb_driver_release_interface(&hci_usb_driver, isocIface); + hUSB->isoc_iface = NULL; + } else { + hUSB->isoc_iface = isocIface; + hUSB->isoc_in_ep = in; + hUSB->isoc_out_ep = out; + } + } + } + set_bit(HCI_USB_TX_WAKEUP, &hUSB->state); + } + +} + + + static struct usb_driver hci_usb_driver = { .name = "hci_usb", .probe = hci_usb_probe, ------=_Part_19967_6038016.1177413190756 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Hi,

As per the discussion on #bluez channel , I am attaching a patch which dynamically manages the the alternate settings for SCO channels.
The patch includes the following :

1. It declares a wor= k queue(config_work), which is scheduled when
    &n= bsp;        1. There is a change in numb= er of SCO channels OR
        &= nbsp;    2. There is a change in the Voice setting.

2. On invocation it determines the alternate setting based on the table given in HCI - usb spec docs. The  table is also mentioned &= nbsp;in the patch.

3. It then empties all the queued isochronous URBs , except = those which are already submitted.

4. It then sets the alternate se= tting by calling   usb_set_interface().

I have tested thi= s patch using "scotest".=20
I am using 2.6.21-rc7 with sco-flowcontrol-v4.2.diff patch.

Let= me know if  any changes are necessary.
Any suggestions are w= elcome.



Alok. 


--- hci_usb.c.orig    2007-04-16 19:37:41.000000000 = +0530
+++ hci_usb.c    2007-04-24 01:41:31.000000000 +053= 0
@@ -47,6 +47,8 @@
 
 #include <linux/usb.h>
&= nbsp;
+#include <linux/workqueue.h>
+
 #include <net/bluetooth/bluetooth.h>
 #include= <net/bluetooth/hci_core.h>
 
@@ -57,6 +59,21 @@
 = #define BT_DBG(D...)
 #endif
 
+/* The number of SCO cha= nnels  */
+int NoSco=3D0;
+/* The  Voice setting  */
+__u16 VocSetting=3D0;
+/* i= f bit=3D0,its 8bit encoding else its 16bit */
+__u16 bit =3D 0x20;
+<= br>+struct hci_usb *hUSB;
+struct usb_device *usbdevice;
+struct us= b_interface *isocIface;
+/* The Workque Function */
+static void set_alternate_config(struct= work_struct *work);
+static DECLARE_WORK(config_work, set_alternate_con= fig);
+
+
 #ifndef CONFIG_BT_HCIUSB_ZERO_PACKET
 #und= ef  URB_ZERO_PACKET
 #define URB_ZERO_PACKET 0
@@ -840,6 +857,10 @@
 static= void hci_usb_notify(struct hci_dev *hdev, unsigned int evt)
 {
=      BT_DBG("%s evt %d", hdev->name, evt);=
+    NoSco =3D hdev->conn_hash.sco_num;
+    VocSetting =3D hdev->voice_setting;
+ &n= bsp;  hUSB =3D (struct hci_usb *) hdev->driver_data;
+ &nbs= p;  schedule_work(&config_work);
 }
 
 sta= tic int hci_usb_probe(struct usb_interface *intf, const struct usb_device_i= d *id)
@@ -854,7 +875,7 @@
     struct hci_usb *husb;     struct hci_dev *hdev;
    = ; int i, e, size, isoc_ifnum, isoc_alts;
-
+    usbdev= ice =3D interface_to_usbdev(intf);
     BT_DBG("= ;udev %p intf %p", udev, intf);
 
     if (!id->driver_info) {
@@ -92= 6,9 +947,11 @@
     isoc_ifnum =3D 1;
 
&= nbsp;#ifdef CONFIG_BT_HCIUSB_SCO
-    if (isoc &&= !(id->driver_info & (HCI_BROKEN_ISOC | HCI_SNIFFER)))
+ &nb= sp;  if (isoc && !(id->driver_info & (HCI_BROKEN_ISOC |= HCI_SNIFFER))){
         isoc_iface =3D usb_ifnum_to= _if(udev, isoc_ifnum);
-
+         = ;   isocIface =3D usb_ifnum_to_if(udev, isoc_ifnum);
+ &n= bsp;  }
+   
     if (isoc_i= face) {
         int a;
 &nbs= p;       struct usb_host_endpoint *isoc_out_ep =3D= NULL;
@@ -1142,6 +1165,121 @@
     return 0;
 = }
 
+
+/*Set the alternate setting based on the number of SCO= channels and the
+  voice setting.This function is invoked when th= ere is a change in Number of
+  SCO channels or when the voice encoding changes.*/
+static void = set_alternate_config(struct work_struct *work)
+{
+   = int isocIfnum=3D1, isocAlt=3D0;
+    struct usb_host_end= point  *ep;
+    struct usb_host_interface *uif;
+    struct _urb *_urb,*_tmp;
+    str= uct _urb_queue *q =3D &hUSB->pending_q[isoc];
+   = unsigned long flags;
+    atomic_t temp;/*Holds the numb= er of URBs we need to skip(which are submitted)*/
+    st= ruct list_head inprocess;/*This list holds the already submitted URBs */
+   
+    /*Change the alternate sett= ing only if the number of SCO channels are more than 1 */
+  &= nbsp; if(NoSco > 0){
+        /* The al= ternate setting selection is based on the following table */
+ &nbs= p;      /*   No. of SCO channels  &= nbsp; Bit-Encoding    Alternate Setting   Max. Pac= ket Size */
+        /*     =       1       &= nbsp;         8bit   = ;            &n= bsp; 1           &nb= sp;      9 */
+      &= nbsp; /*           1 = ;            &n= bsp;  16bit          = ;       2      =            17 */
+&nbs= p;       /*      &nb= sp;    2        &nbs= p;        8bit    &n= bsp;            2&nb= sp;            =     17 */
+        /*     =       2       &= nbsp;        16bit   &nbs= p;             = 4            &n= bsp;    33 */
+        /*&n= bsp;          3  &nb= sp;            =   8bit          &nbs= p;      3       = ;          25 */
+ &nb= sp;      /*       &n= bsp;   3         &nb= sp;      16bit      =            5  &= nbsp;           &nbs= p;  49 */
+        switch(NoSco)
+  &n= bsp;     {
+        case 1:=
+            if(VocSetting= && bit)
+          &nbs= p;     isocAlt=3D2;
+       = ;     else
+         &= nbsp;      isocAlt=3D1;
+     &n= bsp;      break;
+      &nb= sp; case 2:
+            if(VocSetting= && bit)
+          &nbs= p;     isocAlt=3D4;
+       = ;     else
+         &= nbsp;      isocAlt=3D2;
+     &n= bsp;      break;
+      &nb= sp; case 3:
+            if= (VocSetting && bit)
+               = ; isocAlt=3D5;
+           = else
+             &n= bsp;  isocAlt=3D3;
+         &nb= sp;  break;
+        }
+
+ = ;       /*Stop Current TX */
+   = ;     clear_bit(HCI_USB_TX_WAKEUP, &hUSB->state);
+        INIT_LIST_HEAD(&inprocess);
+=         temp =3D hUSB->pending_tx[isoc];+        /*  We cannot purge URBs whic= h have been submitted. inprocess is a */
+      = ;  /*  temporary list which holds the currently submitted URBs. *= /
+        /*  This list is later merg= ed with the emptyed pending queue.  */
+  
+ &nb= sp;      while ((_urb =3D _urb_dequeue(q))) {
+ = ;           /*Dequeue all the submi= tted URBs and put them in the temporary list*/ =20
+            if(!atomic_de= c_and_test(&temp)){
+         &nb= sp;      _urb->queue =3D q;
+    &= nbsp;           list_add(&_urb-= >list, &inprocess);
+         =    }
+           = else{
+             &= nbsp;  /*Unlink all the rest of URBs and put them into the completed q= ueue.*/
+              &= nbsp; _urb_unlink(_urb);
+         &n= bsp;      _urb_queue_tail(__completed_q(hUSB,HCI_SCODAT= A_PKT), _urb);
+           = }
+        }
+     = ;   /*merge the inprocess queue with the pending queue*/
+&nbs= p;       spin_lock_irqsave(&q->lock, flags)= ;
+        list_for_each_entry_safe(_urb, _= tmp, &inprocess, list) {
+        &nbs= p;   list_move_tail(&_urb->list, &q->head);
+&nb= sp;       }
+      &nb= sp; spin_unlock_irqrestore(&q->lock, flags);
+   = =20
+        /* Set the setting and the in/ou= t endpoints */
+        if (isocIface) {+            int e;
+&nbs= p;           struct usb_host_endpoi= nt *out =3D NULL;
+          &nb= sp; struct usb_host_endpoint *in =3D NULL;
+            uif =3D &isoc= Iface->altsetting[isocAlt];
+        &n= bsp;   for (e =3D 0; e < uif->desc.bNumEndpoints; e++) {+              &nbs= p; ep =3D &uif->endpoint[e];
+      &nbs= p;         switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+      &nb= sp;         case USB_ENDPOINT_XFER_ISOC:
+=                =     if (ep->desc.bEndpointAddress & USB_DIR_IN)
+=                =         in  =3D ep;
+  &nb= sp;               &n= bsp; else
+              &= nbsp;         out =3D ep;
+  &nb= sp;               &n= bsp; break;
+            &n= bsp;   }
+          &n= bsp; }
+       
+    &n= bsp;       if (!in || !out)
+   =             BT_DBG("Isoc= endpoints not found");
+            else {
+&n= bsp;               B= T_DBG("isoc ifnum %d alts %d", isocIfnum, isocAlt);
+ &nb= sp;              if (usb_= set_interface(usbdevice, isocIfnum, isocAlt)) {
+    &nbs= p;               BT_= ERR("Can't set isoc interface settings");
+              &= nbsp;     hUSB->isoc_iface =3D isocIface;
+  = ;               &nbs= p;  usb_driver_release_interface(&hci_usb_driver, isocIface);
+=                =     hUSB->isoc_iface =3D NULL;
+    &n= bsp;           } else {
+              &= nbsp;     hUSB->isoc_iface  =3D isocIface;
+ = ;               &nbs= p;   hUSB->isoc_in_ep  =3D in;
+    &nb= sp;               hU= SB->isoc_out_ep  =3D out;
+       =         }
+      = ;      }
+        }+        set_bit(HCI_USB_TX_WAKEUP, &hUS= B->state);
+    }
+
+}

+
+
 static = struct usb_driver hci_usb_driver =3D {
     .name&nb= sp;       =3D "hci_usb",
  =    .probe        =3D hci_usb_probe,=
------=_Part_19967_6038016.1177413190756-- --===============0429618246== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ --===============0429618246== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel --===============0429618246==--