Hi,

Below is a patch with the following changes to the berry_charge.c module:

1) kzalloc() is called, but memory is never freed

        Is this a memory leak?  I'm not sure, but the buffer is only
        a dummy buffer to hold return data that is never used,
        so I suspect a stack variable will suffice.


2) Added pearl mode change

        Blackberry Pearls start out with a Product ID of 0006, and in
        this mode, only a usb mass storage configuration is available.
        This patch sends the required command to change it from 0006
        to 0004, in which both mass storage and the Blackberry
        database configuration are available.

        Also, Pearls need to be reset explicitly before the power change
        takes effect.


3) Added a sleep() for slow devices.

        My kernel-fu is not up to speed, so I'm sure this is the wrong
        fix, and I hope someone recommends the proper one.  Older devices,
        such as the 7750, are slow to reset, and this creates the
        possibility of the kernel going into an endless loop, detecting
        the device and trying to set the power.  The devices, in some
        cases of my testing, never actually changed to 500mA, but
        the kernel was extremely busy trying to do so, and the entire
        USB subsystem seemed to lock up (lsusb would freeze, for example).

        On my system, the sleep gives the device a chance to change to
        500mA, which prevents the endless loop.


- Chris




--- linux-2.6.21.1/drivers/usb/misc/berry_charge.c      2007-04-27 
17:49:26.000000000 -0400
+++ ../linux-2.6.21.1/drivers/usb/misc/berry_charge.c   2007-05-17 
14:56:07.000000000 -0400
@@ -26,6 +26,8 @@
 
 #define RIM_VENDOR             0x0fca
 #define BLACKBERRY             0x0001
+#define PEARL_DUAL             0x0004
+#define PEARL                  0x0006
 
 static int debug;
 
@@ -36,15 +38,22 @@
        if (debug)                                              \
                dev_printk(KERN_DEBUG , dev , format , ## arg)
 
+/* We watch for product IDs 0001 and 0006, with the idea that
+ * for non-Pearl devices, we only change the charging setting,
+ * and for Pearl devices, we change the charge and the mode.
+ * If a Pearl shows up as 0004, we've already seen it and
+ * don't need to mess with it again.
+ */
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(RIM_VENDOR, BLACKBERRY) },
+       { USB_DEVICE(RIM_VENDOR, PEARL) },
        { },                                    /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
 static int magic_charge(struct usb_device *udev)
 {
-       char *dummy_buffer = kzalloc(2, GFP_KERNEL);
+       char dummy_buffer[2];
        int retval;
 
        if (!dummy_buffer)
@@ -78,11 +87,22 @@
                return retval;
        }
 
-       dbg(&udev->dev, "Calling set_configuration\n");
-       retval = usb_driver_set_configuration(udev, 1);
-       if (retval)
-               dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+       return retval;
+}
 
+static int magic_pearl(struct usb_device *udev)
+{
+       char dummy_buffer[2];
+       int retval;
+
+       dbg(&udev->dev, "Sending magic Pearl command\n");
+       retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                                0xa9, 0xc0, 1, 1, dummy_buffer, 2, 100);
+       if (retval != 0) {
+               dev_err(&udev->dev, "Pearl magic command failed: %d.\n",
+                       retval);
+               return retval;
+       }
        return retval;
 }
 
@@ -90,6 +110,9 @@
                       const struct usb_device_id *id)
 {
        struct usb_device *udev = interface_to_usbdev(intf);
+       int retval;
+
+dbg(&udev->dev, "Dev module, version: 2\n");
 
        dbg(&udev->dev, "Power is set to %dmA\n",
            udev->actconfig->desc.bMaxPower * 2);
@@ -105,6 +128,28 @@
        /* turn the power on */
        magic_charge(udev);
 
+       /* change modes if device is a Pearl */
+       if (udev->descriptor.idProduct == PEARL)
+               magic_pearl(udev);
+
+       /* set configuration and reset to activate change */
+       dbg(&udev->dev, "Calling set_configuration\n");
+       retval = usb_driver_set_configuration(udev, 1);
+       if (retval) {
+               dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+               return retval;
+       }
+
+       /* reset is required by the Pearl */
+       retval = usb_reset_configuration(udev);
+       if (retval) {
+               dev_err(&udev->dev, "Configuration reset failed: %d.\n", 
retval);
+               return retval;
+       }
+
+       /* give slower devices a chance to reset properly */
+       ssleep(1);
+
        /* we don't really want to bind to the device, userspace programs can
         * handle the syncing just fine, so get outta here. */
        return -ENODEV;



-------------------------------------------------------------------------
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/
_______________________________________________
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