Skip to contentSkip to conversation

USB: driver for iphone charging

RFC In review Greg KH 4 participants 8 messages Aug 23, 2007 – Aug 25, 2007 USB

lore
Share & tools
lore

Greg KH

author
#0 lore raw

RFC 1/1 USB: driver for iphone charging

my berry_charge code that adds support for charging the iphone when it is plugged into a Linux machine.

As I don't have an iphone, can someone who does please test this out and let me know if it works properly or not?

Matt, I fixed up the formatting of your original driver, fixed a sparse warning, and the memory leak (which happens to also be in the berry_charge driver, I'll go fix that too...)

---
 drivers/usb/Makefile      |    1 
 drivers/usb/misc/Kconfig  |   11 ++++
 drivers/usb/misc/Makefile |    1 
 drivers/usb/misc/iphone.c |  107 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 120 insertions(+)
drivers/usb/Makefile +1 -0
@@ -40,6 +40,7 @@ obj-$(CONFIG_USB_FTDI_ELAN)	+= misc/
 obj-$(CONFIG_USB_GOTEMP)	+= misc/
 obj-$(CONFIG_USB_IDMOUSE)	+= misc/
 obj-$(CONFIG_USB_IOWARRIOR)	+= misc/
+obj-$(CONFIG_USB_IPHONE)	+= misc/
 obj-$(CONFIG_USB_LCD)		+= misc/
 obj-$(CONFIG_USB_LD)		+= misc/
 obj-$(CONFIG_USB_LED)		+= misc/
drivers/usb/misc/Kconfig +11 -0
@@ -99,6 +99,17 @@ config USB_BERRY_CHARGE
 	  To compile this driver as a module, choose M here: the
 	  module will be called berry_charge.
 
+config USB_IPHONE
+	tristate "USB iPhone recharge support"
+	depends on USB
+	help
+	  Say Y here if you want to connect a iPhone device to your
+	  computer's USB port and have it automatically switch to "recharge"
+	  mode.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iphone.
+
 config USB_LED
 	tristate "USB LED driver support"
 	depends on USB
drivers/usb/misc/Makefile +1 -0
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_FTDI_ELAN)	+= ftdi-elan
 obj-$(CONFIG_USB_GOTEMP)	+= gotemp.o
 obj-$(CONFIG_USB_IDMOUSE)	+= idmouse.o
 obj-$(CONFIG_USB_IOWARRIOR)	+= iowarrior.o
+obj-$(CONFIG_USB_IPHONE)	+= iphone.o
 obj-$(CONFIG_USB_LCD)		+= usblcd.o
 obj-$(CONFIG_USB_LD)		+= ldusb.o
 obj-$(CONFIG_USB_LED)		+= usbled.o
drivers/usb/misc/iphone.c new file +107 -0

107 lines not on this page · raw message

#1 lore raw

Am Freitag 24 August 2007 schrieb Greg KH:

Hi,

Quoted 9 lines
drivers/usb/misc/iphone.c new file +9 -0
+static int select_configuration(struct usb_device *udev)
+{
+       char *dummy_buffer = kzalloc(2, GFP_KERNEL);
+       int retval;
+
+       if (!dummy_buffer)
+               return -ENOMEM;
+
+       dbg(&udev->dev, "Calling set_configuration\n");

drivers/usb/misc/iphone.c line 56

Quoted 10 lines
drivers/usb/misc/iphone.c new file +10 -0
+       retval = usb_driver_set_configuration(udev, 3);
+       if (retval) {
+               dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+               goto exit;
+       }
+
+       dbg(&udev->dev, "Sending first magic command\n");
+       retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x40, 0x40,
+                                0x6400, 0, dummy_buffer, 0, 100);
+

int usb_driver_set_configuration(struct usb_device *udev, int config)

{
	struct set_config_request *req;

	req = kmalloc(sizeof(*req), GFP_KERNEL);
	if (!req)
		return -ENOMEM;
	req->udev = udev;
	req->config = config;
	INIT_WORK(&req->work, driver_set_config_work);

	usb_get_dev(udev);
	schedule_work(&req->work);
	return 0;
}

This schedules the change via a workqueue, so you'll be reprobed. If you fire of the first vendor command you are doing so before the configuration is changed. How is this supposed to work?

Regards
Oliver

#2 lore raw
Quoted 3 lines · Oliver Neukum

This schedules the change via a workqueue, so you'll be reprobed. If you fire of the first vendor command you are doing so before the configuration is changed. How is this supposed to work?

I would do it like this:

static int iphone_probe(struct usb_interface *intf,
const struct usb_device_id *id)

{
	struct usb_device *udev = interface_to_usbdev(intf);
	int rc;

	if (udev->actconfig->desc.bConfigurationValue != 3) {
		dbg(&udev->dev, "Calling set_configuration\n");
		rc = usb_driver_set_configuration(udev, 3);
	} else {
		dbg(&udev->dev, "Configuration set, sending magic comand\n");
		rc = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
				0x40, (USB_DIR_OUT | USB_TYPE_VENDOR |
					USB_RECIP_DEVICE),
				0x6400, 0, NULL, 0, 1000);
	}
	if (rc)
		dev_err(&udev->dev, "Command failed: %d\n", rc);

	/* we don't really want to bind to the device, userspace programs can
	 * handle the syncing just fine, so get outta here. */
	return -ENODEV;
}

Alan Stern

#3 lore raw

Am Freitag 24 August 2007 schrieb Alan Stern:

Quoted 7 lines · Oliver Neukum
Quoted 4 lines

This schedules the change via a workqueue, so you'll be reprobed. If you fire of the first vendor command you are doing so before the configuration is changed. How is this supposed to work?

I would do it like this:

That makes sense. However, Greg's version might work by putting out a magic init sequence and then changing the configuration. Then it would just be coded in an obscure way.

However, does this really belong into kernel space? We have been knowing that user space infrastructure for configuration selection is necessary and this seems like a fine starting point.

Regards
Oliver

author
#4 lore raw
Quoted 7 lines · Oliver Neukum

Am Freitag 24 August 2007 schrieb Alan Stern:

Quoted 6 lines · Oliver Neukum
Quoted 4 lines

This schedules the change via a workqueue, so you'll be reprobed. If you fire of the first vendor command you are doing so before the configuration is changed. How is this supposed to work?

Quoted 5 lines
Quoted 1 line

I would do it like this:

That makes sense. However, Greg's version might work by putting out a magic init sequence and then changing the configuration. Then it would just be coded in an obscure way.

Without any docs, this is all obscure :)

Quoted 3 lines

However, does this really belong into kernel space? We have been knowing that user space infrastructure for configuration selection is necessary and this seems like a fine starting point.

The berry_charge driver is also one that might be done in userspace, but it turns out that people update their kernel much more than they do userspace packages...

thanks,

greg k-h

author
#5 lore raw
In reply to Alan Stern
Quoted 23 lines · Alan Stern
Quoted 3 lines · Oliver Neukum

This schedules the change via a workqueue, so you'll be reprobed. If you fire of the first vendor command you are doing so before the configuration is changed. How is this supposed to work?

I would do it like this:

static int iphone_probe(struct usb_interface *intf,
const struct usb_device_id *id)

{
	struct usb_device *udev = interface_to_usbdev(intf);
	int rc;

	if (udev->actconfig->desc.bConfigurationValue != 3) {
		dbg(&udev->dev, "Calling set_configuration\n");
		rc = usb_driver_set_configuration(udev, 3);
	} else {
		dbg(&udev->dev, "Configuration set, sending magic comand\n");
		rc = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
				0x40, (USB_DIR_OUT | USB_TYPE_VENDOR |
					USB_RECIP_DEVICE),
				0x6400, 0, NULL, 0, 1000);
Quoted 8 lines
	}
	if (rc)
		dev_err(&udev->dev, "Command failed: %d\n", rc);

	/* we don't really want to bind to the device, userspace programs can
	 * handle the syncing just fine, so get outta here. */
	return -ENODEV;
}

Yeah, that would make more sense, if that is what is needed.

Can someone with a iphone test this out? If you look at how the berry_charge driver does it, the set_config stuff happens after the magic command. As I don't have an iphone, nor have I ever seen any dumps of the command streams, I don't really know if the set_config message really is necessary or not.

thanks,

greg k-h

#6 lore raw
Quoted 5 lines · Greg KH

Can someone with a iphone test this out? If you look at how the berry_charge driver does it, the set_config stuff happens after the magic command. As I don't have an iphone, nor have I ever seen any dumps of the command streams, I don't really know if the set_config message really is necessary or not.

You know, now that I think back on it, it may be that the Set-Config really does have to come after the magic command. Perhaps it triggers the changeover. In which case the subroutine should look like this:

static int iphone_probe(struct usb_interface *intf,
const struct usb_device_id *id)

{
	struct usb_device *udev = interface_to_usbdev(intf);
	int rc;

	if (udev->actconfig->desc.bConfigurationValue != 3) {
		dbg(&udev->dev, "Sending magic comand\n");
		rc = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
				0x40, (USB_DIR_OUT | USB_TYPE_VENDOR |
					USB_RECIP_DEVICE),
				0x6400, 0, NULL, 0, 1000);
		if (rc)
			dev_err(&udev->dev, "Command failed: %d\n", rc);
		else {
			dbg(&udev->dev, "Calling set_configuration\n");
			rc = usb_driver_set_configuration(udev, 3);
			if (rc)
				dev_err(&udev->dev, "Set-Config failed: %d\n",
						rc);
		}
	}

	/* we don't really want to bind to the device, userspace programs can
	 * handle the syncing just fine, so get outta here. */
	return -ENODEV;
}

However Oliver's point is well taken. This simple sort of manipulation could easily be done by a user program, started up by udev.

Alan Stern

#7 lore raw
Quoted 8 lines · Alan Stern
Quoted 5 lines · Greg KH

Can someone with a iphone test this out? If you look at how the berry_charge driver does it, the set_config stuff happens after the magic command. As I don't have an iphone, nor have I ever seen any dumps of the command streams, I don't really know if the set_config message really is necessary or not.

Quoted 4 lines

You know, now that I think back on it, it may be that the Set-Config really does have to come after the magic command. Perhaps it triggers the changeover. In which case the subroutine should look like this:

Hi all,
I was the one who wrote the patch initially (sorry I haven't been able
to chime in sooner). It turns out that the configuration must be set after the magic command (I tried both versions of the code tonight and only the one which changes the configuration after the command works). That said, I am not opposed to using a userspace program to accomplish this task (I tried to pursue that avenue at first and couldn't find a way to do, probably because it doesn't exist yet). I don't really have much experience in this area, so I am not really sure how to proceed.

However the other part of this puzzle is that when you call lsusb the iPhone disconnects from the bus. Greg suggested that it might be an issue with the USB_SUSPEND support being broken on the iPhone and he suggested I tried adding it to the quirks.c file. I'll be sure to let you guys know when I figure it out.

-Matt