Author: n_hibma
Date: Fri Feb 13 19:49:51 2009
New Revision: 188597
URL: http://svn.freebsd.org/changeset/base/188597

Log:
  Add support for CMOTECH devices (not sure whether this is the correct
  name) (not sure whether this works correctly, but should be close).
  
  Fix the stub attach phase for some Novatel cards. They expect the CSW
  (repsonse to CBW, SCSI eject command) to be fetched before switching to
  modem mode.
  
  MFC after:    2 weeks

Modified:
  head/sys/dev/usb/u3g.c
  head/sys/dev/usb/usbdevs

Modified: head/sys/dev/usb/u3g.c
==============================================================================
--- head/sys/dev/usb/u3g.c      Fri Feb 13 19:49:35 2009        (r188596)
+++ head/sys/dev/usb/u3g.c      Fri Feb 13 19:49:51 2009        (r188597)
@@ -87,25 +87,25 @@ struct ucom_callback u3g_callback = {
 
 
 struct u3g_speeds_s {
-       u_int32_t               ispeed;         // Speed in bits per second
-       u_int32_t               ospeed;         // Speed in bits per second
+       u_int32_t               ispeed;
+       u_int32_t               ospeed;
 };
 
 static const struct u3g_speeds_s u3g_speeds[] = {
-#define U3GSP_GPRS             0
-       {64000,   64000},
-#define U3GSP_EDGE             1
-       {384000,  64000},
-#define U3GSP_CDMA             2
-       {384000,  64000},
-#define U3GSP_UMTS             3
-       {384000,  64000},
-#define U3GSP_HSDPA            4
-       {1200000, 384000},
-#define U3GSP_HSUPA            5
-       {1200000, 384000},
-#define U3GSP_HSPA             6
-       {7200000, 384000},
+#define U3GSP_GPRS     0
+       {64000,         64000},
+#define U3GSP_EDGE     1
+       {384000,        64000},
+#define U3GSP_CDMA     2
+       {384000,        64000},
+#define U3GSP_UMTS     3
+       {384000,        64000},
+#define U3GSP_HSDPA    4
+       {1200000,       384000},
+#define U3GSP_HSUPA    5
+       {1200000,       384000},
+#define U3GSP_HSPA     6
+       {7200000,       384000},
 };
 
 #define U3GIBUFSIZE    1024
@@ -122,7 +122,8 @@ struct u3g_dev_type_s {
 #define U3GFL_HUAWEI_INIT      0x01            // Requires init command 
(Huawei cards)
 #define U3GFL_SCSI_EJECT       0x02            // Requires SCSI eject command 
(Novatel)
 #define U3GFL_SIERRA_INIT      0x04            // Requires init command 
(Sierra cards)
-#define U3GFL_STUB_WAIT                0x08            // Device reappears 
after a short delay
+#define U3GFL_CMOTECH_INIT     0x08            // Requires init command 
(CMOTECH cards)
+#define U3GFL_STUB_WAIT                0x80            // Device reappears 
after a short delay
 };
 
 // Note: The entries marked with XXX should be checked for the correct speed
@@ -184,10 +185,13 @@ static const struct u3g_dev_type_s u3g_d
        {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 },              
U3GSP_UMTS,     U3GFL_NONE },           // XXX
        {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U },              
U3GSP_UMTS,     U3GFL_NONE },           // XXX
        {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 },            
U3GSP_HSDPA,    U3GFL_NONE },           // XXX
-       {{ USB_VENDOR_HP, USB_PRODUCT_HP_HS2300 },                      
U3GSP_HSDPA,    U3GFL_NONE },           // XXX
        {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 },              
U3GSP_UMTS,     U3GFL_NONE },           // XXX
        {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 },              
U3GSP_UMTS,     U3GFL_NONE },           // XXX
-       {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_TRUINSTALL },          
U3GSP_UMTS,     U3GFL_SIERRA_INIT },    // Sierra TruInstaller device ID
+       {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_TRUINSTALL },          
U3GSP_UMTS,     U3GFL_SIERRA_INIT },
+       {{ USB_VENDOR_HP, USB_PRODUCT_HP_HS2300 },                      
U3GSP_HSDPA,    U3GFL_NONE },
+       /* OEM: CMOTECH */
+       {{ USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CGU628 },            
U3GSP_HSDPA,    U3GFL_CMOTECH_INIT },
+       {{ USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_DISK },              
U3GSP_HSDPA,    U3GFL_NONE },
 };
 #define u3g_lookup(v, p) ((const struct u3g_dev_type_s *)usb_lookup(u3g_devs, 
v, p))
 
@@ -437,7 +441,7 @@ MODULE_VERSION(u3g, 1);
 struct u3gstub_softc {
        device_t                sc_dev;
        usbd_device_handle      sc_udev;
-       usbd_pipe_handle        sc_pipe;
+       usbd_pipe_handle        sc_pipe_out, sc_pipe_in;
        usbd_xfer_handle        sc_xfer;
 };
 
@@ -457,6 +461,25 @@ u3gstub_huawei_init(struct u3gstub_softc
        return 1;
 }
 
+static void
+u3gstub_BBB_cb(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status 
err)
+{
+       struct u3gstub_softc *sc = (struct u3gstub_softc *) priv;
+       unsigned char cmd[13];
+
+       if (err) {
+               device_printf(sc->sc_dev,
+                             "Failed to send CD eject command to "
+                             "change to modem mode\n");
+       } else {
+               usbd_setup_xfer(sc->sc_xfer, sc->sc_pipe_in, NULL, cmd, 
sizeof(cmd),
+                               0, USBD_DEFAULT_TIMEOUT, NULL);
+               int err = usbd_transfer(sc->sc_xfer) != USBD_NORMAL_COMPLETION;
+               if (err != USBD_NORMAL_COMPLETION && err != USBD_IN_PROGRESS)
+                       DPRINTF("failed to start transfer (CSW)\n");
+       }
+}
+
 static int
 u3gstub_scsi_eject(struct u3gstub_softc *sc, struct usb_attach_arg *uaa)
 {
@@ -467,7 +490,7 @@ u3gstub_scsi_eject(struct u3gstub_softc 
            0x55, 0x53, 0x42, 0x43,     /* 0..3: Command Block Wrapper (CBW) 
signature */
            0x01, 0x00, 0x00, 0x00,     /* 4..7: CBW Tag, unique 32-bit number 
*/
            0x00, 0x00, 0x00, 0x00,     /* 8..11: CBW Transfer Length, no data 
here */
-           0x00,                       /* 12: CBW Flag: output, so 0 */
+           0x00,                       /* 12: CBW Flag: output */
            0x00,                       /* 13: CBW Lun */
            0x06,                       /* 14: CBW Length */
 
@@ -488,11 +511,33 @@ u3gstub_scsi_eject(struct u3gstub_softc 
 
        /* Find the bulk-out endpoints */
        id = usbd_get_interface_descriptor(uaa->iface);
-       for (i = 0 ; i < id->bNumEndpoints ; i++) {
+       for (i = 0 ; i < id->bNumEndpoints; i++) {
                ed = usbd_interface2endpoint_descriptor(uaa->iface, i);
                if (ed != NULL
-                   && UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT
-                   && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK)
+                   && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
+                       if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) {
+                               if (usbd_open_pipe(uaa->iface,
+                                                  ed->bEndpointAddress,
+                                                  USBD_EXCLUSIVE_USE,
+                                                  &sc->sc_pipe_out)
+                                   != USBD_NORMAL_COMPLETION) {
+                                       DPRINTF("failed to open bulk-out pipe 
on endpoint %d\n",
+                                               ed->bEndpointAddress);
+                                       return 0;
+                               }
+                       } else {
+                               if (usbd_open_pipe(uaa->iface,
+                                                  ed->bEndpointAddress,
+                                                  USBD_EXCLUSIVE_USE,
+                                                  &sc->sc_pipe_in)
+                                   != USBD_NORMAL_COMPLETION) {
+                                       DPRINTF("failed to open bulk-in pipe on 
endpoint %d\n",
+                                               ed->bEndpointAddress);
+                                       return 0;
+                               }
+                       }
+               }
+               if (sc->sc_pipe_out && sc->sc_pipe_in)
                        break;
        }
 
@@ -501,10 +546,88 @@ u3gstub_scsi_eject(struct u3gstub_softc 
                return 0;
        }
 
-       if (usbd_open_pipe(uaa->iface, ed->bEndpointAddress,
-                          USBD_EXCLUSIVE_USE, &sc->sc_pipe) != 
USBD_NORMAL_COMPLETION) {
-               DPRINTF("failed to open bulk-out pipe on endpoint %d\n",
-                       ed->bEndpointAddress);
+       sc->sc_xfer = usbd_alloc_xfer(uaa->device);
+       if (sc->sc_xfer == NULL) {
+               DPRINTF("failed to allocate xfer\n");
+               return 0;
+       }
+
+       usbd_setup_xfer(sc->sc_xfer, sc->sc_pipe_out, NULL, cmd, sizeof(cmd),
+                       0, USBD_DEFAULT_TIMEOUT, u3gstub_BBB_cb);
+       int err = usbd_transfer(sc->sc_xfer) != USBD_NORMAL_COMPLETION;
+       if (err != USBD_NORMAL_COMPLETION && err != USBD_IN_PROGRESS) {
+               DPRINTF("failed to start transfer (CBW)\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static int
+u3gstub_cmotech_init(struct u3gstub_softc *sc, struct usb_attach_arg *uaa)
+{
+       /* See definition of umass_bbb_cbw_t in sys/dev/usb/umass.c
+        * in sys/cam/scsi/scsi_all.h .
+         */
+       unsigned char cmd[31] = {
+           0x55, 0x53, 0x42, 0x43,     /* 0..3: Command Block Wrapper (CBW) 
signature */
+           0x01, 0x00, 0x00, 0x00,     /* 4..7: CBW Tag, unique 32-bit number 
*/
+           0x00, 0x00, 0x00, 0x00,     /* 8..11: CBW Transfer Length, no data 
here */
+           0x80,                       /* 12: CBW Flag: output, so 0 */
+           0x00,                       /* 13: CBW Lun */
+           0x08,                       /* 14: CBW Length */
+
+           0xff,                       /* 15+0 */
+           0x52,                       /* 15+1 */
+           0x44,                       /* 15+2 */
+           0x45,                       /* 15+2 */
+           0x56,                       /* 15+4 */
+           0x43,                       /* 15+5 */
+           0x48,                       /* 15+5 */
+           0x47,                       /* 15+5 */
+           0x00, 0x00, 0x00, 0x00,     /* 15+8..15: unused */
+           0x00, 0x00, 0x00, 0x00
+       };
+
+       usb_interface_descriptor_t *id;
+       usb_endpoint_descriptor_t *ed = NULL;
+       int i;
+
+
+       /* Find the bulk-out endpoints */
+       id = usbd_get_interface_descriptor(uaa->iface);
+       for (i = 0 ; i < id->bNumEndpoints ; i++) {
+               ed = usbd_interface2endpoint_descriptor(uaa->iface, i);
+               if (ed != NULL
+                   && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
+                       if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) {
+                               if (usbd_open_pipe(uaa->iface,
+                                                  ed->bEndpointAddress,
+                                                  USBD_EXCLUSIVE_USE,
+                                                  &sc->sc_pipe_out)
+                                   != USBD_NORMAL_COMPLETION) {
+                                       DPRINTF("failed to open bulk-out pipe 
on endpoint %d\n",
+                                               ed->bEndpointAddress);
+                                       return 0;
+                               }
+                       } else {
+                               if (usbd_open_pipe(uaa->iface,
+                                                  ed->bEndpointAddress,
+                                                  USBD_EXCLUSIVE_USE,
+                                                  &sc->sc_pipe_in)
+                                   != USBD_NORMAL_COMPLETION) {
+                                       DPRINTF("failed to open bulk-in pipe on 
endpoint %d\n",
+                                               ed->bEndpointAddress);
+                                       return 0;
+                               }
+                       }
+               }
+               if (sc->sc_pipe_out && sc->sc_pipe_in)
+                       break;
+       }
+
+       if (i == id->bNumEndpoints) {
+               DPRINTF("failed to find bulk-out pipe\n");
                return 0;
        }
 
@@ -514,11 +637,11 @@ u3gstub_scsi_eject(struct u3gstub_softc 
                return 0;
        }
 
-       usbd_setup_xfer(sc->sc_xfer, sc->sc_pipe, NULL, cmd, sizeof(cmd),
-                       0, USBD_DEFAULT_TIMEOUT, NULL);
+       usbd_setup_xfer(sc->sc_xfer, sc->sc_pipe_out, NULL, cmd, sizeof(cmd),
+                       0, USBD_DEFAULT_TIMEOUT, u3gstub_BBB_cb);
        int err = usbd_transfer(sc->sc_xfer) != USBD_NORMAL_COMPLETION;
        if (err != USBD_NORMAL_COMPLETION && err != USBD_IN_PROGRESS) {
-               DPRINTF("failed to start transfer\n");
+               DPRINTF("failed to start transfer (CBW)\n");
                return 0;
        }
 
@@ -563,6 +686,7 @@ u3gstub_match(device_t self)
        if (u3g_dev_type->flags&U3GFL_HUAWEI_INIT
            || u3g_dev_type->flags&U3GFL_SCSI_EJECT
            || u3g_dev_type->flags&U3GFL_SIERRA_INIT
+           || u3g_dev_type->flags&U3GFL_CMOTECH_INIT
            || u3g_dev_type->flags&U3GFL_STUB_WAIT) {
                /* We assume that if the first interface is still a mass
                 * storage device the device has not yet changed appearance.
@@ -620,6 +744,12 @@ u3gstub_attach(device_t self)
                                      "changing Sierra modem to modem mode\n");
                if (!u3gstub_sierra_init(sc, uaa))
                        return ENXIO;
+       } else if (u3g_dev_type->flags&U3GFL_CMOTECH_INIT) {
+               if (bootverbose)
+                       device_printf(sc->sc_dev,
+                                     "changing CMOTECH modem to modem mode\n");
+               if (!u3gstub_cmotech_init(sc, uaa))
+                       return ENXIO;
        } else if (u3g_dev_type->flags&U3GFL_STUB_WAIT) {
                if (bootverbose)
                        device_printf(sc->sc_dev, "waiting for modem to change "
@@ -638,9 +768,13 @@ u3gstub_detach(device_t self)
        if (sc->sc_xfer)
                usbd_free_xfer(sc->sc_xfer);
 
-       if (sc->sc_pipe) {
-               usbd_abort_pipe(sc->sc_pipe);
-               usbd_close_pipe(sc->sc_pipe);
+       if (sc->sc_pipe_in) {
+               usbd_abort_pipe(sc->sc_pipe_in);
+               usbd_close_pipe(sc->sc_pipe_in);
+       }
+       if (sc->sc_pipe_out) {
+               usbd_abort_pipe(sc->sc_pipe_out);
+               usbd_close_pipe(sc->sc_pipe_out);
        }
 
        return 0;

Modified: head/sys/dev/usb/usbdevs
==============================================================================
--- head/sys/dev/usb/usbdevs    Fri Feb 13 19:49:35 2009        (r188596)
+++ head/sys/dev/usb/usbdevs    Fri Feb 13 19:49:51 2009        (r188597)
@@ -613,7 +613,7 @@ vendor GIGASET              0x1690  Gigaset
 vendor GLOBALSUN       0x16ab  Global Sun Technology
 vendor ANYDATA         0x16d5  AnyDATA Corporation
 vendor JABLOTRON       0x16d6  Jablotron
-vendor CMOTECH         0x16d8  CMOTECH Co., Ltd.
+vendor CMOTECH         0x16d8  C-motech
 vendor AXESSTEL                0x1726  Axesstel Co., Ltd.
 vendor LINKSYS4                0x1737  Linksys
 vendor SENAO           0x1740  Senao
@@ -1030,9 +1030,11 @@ product CISCOLINKSYS WUSB54GR    0x0023  WUS
 product CISCOLINKSYS WUSBF54G  0x0024  WUSBF54G
 
 /* CMOTECH products */
-product CMOTECH CNU510         0x5141  CMOTECH CDMA Technologies USB modem
+product CMOTECH CNU510         0x5141  CDMA Technologies USB modem
 product CMOTECH CNU550         0x5543  CDMA 2000 1xRTT/1xEVDO USB modem
-product CMOTECH CDMA_MODEM1    0x6280  CMOTECH CDMA Technologies USB modem
+product CMOTECH CGU628         0x6006  CGU-628
+product CMOTECH CDMA_MODEM1    0x6280  CDMA Technologies USB modem
+product CMOTECH DISK           0xf000  disk mode
 
 /* Compaq products */
 product COMPAQ IPAQPOCKETPC    0x0003  iPAQ PocketPC
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to