Add Apple MFi fastcharge USB device driver
v3 cover Add Apple MFi fastcharge USB device driver
This is version 3 of the patch set.
Changes in v3:
- Add Alan's ack
- don't export usb_device_match_id()
Changes in v2:
- checkpatch.pl is now quiet
- fallback to the generic driver when driver ->probe() fails
Bastien Nocera (6):
USB: Export generic USB device driver functions
USB: Make it possible to "subclass" usb_device_driver
USB: Implement usb_device_match_id()
USB: Select better matching USB drivers when available
USB: Fallback to generic driver when specific driver fails
USB: Add driver to control USB fast charge for iOS devices
MAINTAINERS | 6 + drivers/usb/core/driver.c | 58 +++++- drivers/usb/core/generic.c | 48 ++++- drivers/usb/core/usb.h | 8 + drivers/usb/misc/Kconfig | 10 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/apple-mfi-fastcharge.c | 237 ++++++++++++++++++++++++ include/linux/usb.h | 7 + 8 files changed, 360 insertions(+), 15 deletions(-) create mode 100644 drivers/usb/misc/apple-mfi-fastcharge.c
Signature · 1 line
2.21.0
PATCH v3 1/6 USB: Export generic USB device driver functions
This will make it possible to implement device drivers which extend the generic driver without needing to reimplement it.
--- drivers/usb/core/generic.c | 16 ++++++++-------- drivers/usb/core/usb.h | 6 ++++++ 2 files changed, 14 insertions(+), 8 deletions(-)
usb/core/generic.c +8 -8
@@ -195,7 +195,7 @@ int usb_choose_configuration(struct usb_device *udev) }EXPORT_SYMBOL_GPL (usb_choose_configuration); -static int generic_probe (struct usb_device *udev) +int usb_generic_driver_probe (struct usb_device *udev) {int err, c;
@@ -222,7 +222,7 @@ static int generic_probe(struct usb_device *udev)return 0 ; } -static void generic_disconnect (struct usb_device *udev) +void usb_generic_driver_disconnect (struct usb_device *udev) {usb_notify_remove_device (udev);
@@ -234,7 +234,7 @@ static void generic_disconnect(struct usb_device *udev)#ifdef CONFIG_PM -static int generic_suspend (struct usb_device *udev,pm_message_t msg) +int usb_generic_driver_suspend (struct usb_device *udev,pm_message_t msg) {int rc;
@@ -262,7 +262,7 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)return rc; } -static int generic_resume (struct usb_device *udev,pm_message_t msg) +int usb_generic_driver_resume (struct usb_device *udev,pm_message_t msg) {int rc;
@@ -285,11 +285,11 @@ static int generic_resume(struct usb_device *udev, pm_message_t msg)struct usb_device_driver usb_generic_driver = { .name ="usb" , - .probe = generic_probe, - .disconnect = generic_disconnect, + .probe = usb_generic_driver_probe, + .disconnect = usb_generic_driver_disconnect, #ifdef CONFIG_PM - .suspend = generic_suspend, - .resume = generic_resume, + .suspend = usb_generic_driver_suspend, + .resume = usb_generic_driver_resume, #endif .supports_autosuspend =1 , };
usb/core/usb.h +6 -0
@@ -47,6 +47,12 @@ extern void usb_release_bos_descriptor(struct usb_device *dev);extern char *usb_cache_string (struct usb_device *udev,int index);extern int usb_set_configuration (struct usb_device *dev,int configuration);extern int usb_choose_configuration (struct usb_device *udev); +extern int usb_generic_driver_probe (struct usb_device *udev); +extern void usb_generic_driver_disconnect (struct usb_device *udev); +extern int usb_generic_driver_suspend (struct usb_device *udev, +pm_message_t msg); +extern int usb_generic_driver_resume (struct usb_device *udev, +pm_message_t msg);static inline unsigned usb_get_max_power (struct usb_device *udev,struct usb_host_config *c)
Signature · 1 line
2.21.0
PATCH v3 2/6 USB: Make it possible to "subclass" usb_device_driver
In reply to Bastien NoceraThe kernel currenly has only 2 usb_device_drivers, one generic one, one that completely replaces the generic one to make USB devices usable over a network.
Use the newly exported generic driver functions when a driver declares to want them run, in addition to its own code. This makes it possible to write drivers that extend the generic USB driver.
Note that this patch is not enough for another driver to automatically get selected.
--- drivers/usb/core/driver.c | 26 +++++++++++++++++++++----- include/linux/usb.h | 4 ++++ 2 files changed, 25 insertions(+), 5 deletions(-)
usb/core/driver.c +21 -5
@@ -261,9 +261,16 @@ static int usb_probe_device(struct device *dev)*/ if (!udriver->supports_autosuspend) error =usb_autoresume_device (udev); +if (error) +return error; -if (!error) - error = udriver->probe (udev); +if (udriver->generic_subclass) + error =usb_generic_driver_probe (udev); +if (error) +return error; + + error = udriver->probe (udev); +/* TODO: fallback to generic driver in case of error */ return error; }
@@ -273,7 +280,10 @@ static int usb_unbind_device(struct device *dev)struct usb_device *udev =to_usb_device (dev);struct usb_device_driver *udriver =to_usb_device_driver (dev->driver); - udriver->disconnect (udev); +if (udriver->disconnect) + udriver->disconnect (udev); +if (udriver->generic_subclass) +usb_generic_driver_disconnect (udev);if (!udriver->supports_autosuspend)usb_autosuspend_device (udev);return 0 ;
@@ -1149,7 +1159,10 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg) udev->do_remote_wakeup =0 ; udriver = &usb_generic_driver; } - status = udriver->suspend (udev, msg); +if (udriver->suspend) + status = udriver->suspend (udev, msg); +if (status ==0 && udriver->generic_subclass) + status =usb_generic_driver_suspend (udev, msg); done:dev_vdbg (&udev->dev,"%s: status %d\n" , __func__, status);
@@ -1181,7 +1194,10 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg) udev->reset_resume =1 ; udriver =to_usb_device_driver (udev->dev.driver); - status = udriver->resume (udev, msg); +if (udriver->generic_subclass) + status =usb_generic_driver_resume (udev, msg); +if (status ==0 && udriver->resume) + status = udriver->resume (udev, msg); done:dev_vdbg (&udev->dev,"%s: status %d\n" , __func__, status);
linux/usb.h +4 -0
@@ -1228,6 +1228,9 @@ struct usb_driver {* @drvwrap: Driver-model core structure wrapper. * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend * for devices bound to this driver. +* @generic_subclass: if set to 1, the generic USB driver's probe, disconnect, +* resume and suspend functions will be called in addition to the driver's +* own, so this part of the setup does not need to be replicated. * * USB drivers must provide all the fields listed above except drvwrap. */
@@ -1242,6 +1245,7 @@ struct usb_device_driver {const struct attribute_group **dev_groups;struct usbdrv_wrap drvwrap; unsigned int supports_autosuspend:1; + unsigned int generic_subclass:1; };#define to_usb_device_driver (d) container_of(d, struct usb_device_driver, \ drvwrap.driver)
Signature · 1 line
2.21.0
PATCH v3 3/6 USB: Implement usb_device_match_id()
In reply to Bastien NoceraMatch a usb_device with a table of IDs.
--- drivers/usb/core/driver.c | 14 ++++++++++++++ drivers/usb/core/usb.h | 2 ++ 2 files changed, 16 insertions(+)
usb/core/driver.c +14 -0
@@ -800,6 +800,20 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface, }EXPORT_SYMBOL_GPL (usb_match_id); +const struct usb_device_id *usb_device_match_id (struct usb_device *udev, +const struct usb_device_id *id) +{ +if (!id) +return NULL ; + +for (; id->idVendor || id->idProduct ; id++) { +if (usb_match_device (udev, id)) +return id; + } + +return NULL ; +} +static int usb_device_match (struct device *dev,struct device_driver *drv) {/* devices and interfaces are handled separately */
usb/core/usb.h +2 -0
@@ -69,6 +69,8 @@ extern int usb_match_one_id_intf(struct usb_device *dev, const struct usb_device_id *id);extern int usb_match_device (struct usb_device *dev,const struct usb_device_id *id); +extern const struct usb_device_id *usb_device_match_id (struct usb_device *udev, +const struct usb_device_id *id);extern void usb_forced_unbind_intf (struct usb_interface *intf);extern void usb_unbind_and_rebind_marked_interfaces (struct usb_device *udev);
Signature · 1 line
2.21.0
PATCH v3 4/6 USB: Select better matching USB drivers when available
In reply to Bastien NoceraNow that USB device drivers can reuse code from the generic USB device driver, we need to make sure that they get selected rather than the generic driver. Add an id_table and match vfunc to the usb_device_driver struct, which will get used to select a better matching driver at ->probe time.
This is a similar mechanism to that used in the HID drivers, with the generic driver being selected unless there's a better matching one found in the registered drivers (see hid_generic_match() in drivers/hid/hid-generic.c).
--- drivers/usb/core/driver.c | 15 +++++++++++++-- drivers/usb/core/generic.c | 29 +++++++++++++++++++++++++++++ include/linux/usb.h | 2 ++ 3 files changed, 44 insertions(+), 2 deletions(-)
usb/core/driver.c +13 -2
@@ -818,13 +818,24 @@ static int usb_device_match(struct device *dev, struct device_driver *drv) {/* devices and interfaces are handled separately */ if (is_usb_device (dev)) { +struct usb_device *udev; +struct usb_device_driver *udrv;/* interface drivers never match devices */ if (!is_usb_device_driver (drv))return 0 ; -/* TODO: Add real matching code */ -return 1 ; + udev =to_usb_device (dev); + udrv =to_usb_device_driver (drv); + +if (udrv->id_table && +usb_device_match_id (udev, udrv->id_table) !=NULL ) { +return 1 ; + } + +if (udrv->match) +return udrv->match (udev); +return 0 ; }else if (is_usb_interface (dev)) {struct usb_interface *intf;
usb/core/generic.c +29 -0
@@ -195,6 +195,34 @@ int usb_choose_configuration(struct usb_device *udev) }EXPORT_SYMBOL_GPL (usb_choose_configuration); +static int __check_usb_generic (struct device_driver *drv,void *data) +{ +struct usb_device *udev = data; +struct usb_device_driver *udrv; + +if (!is_usb_device_driver (drv)) +return 0 ; + udrv =to_usb_device_driver (drv); +if (udrv == &usb_generic_driver) +return 0 ; +if (!udrv->id_table) +return 0 ; + +return usb_device_match_id (udev, udrv->id_table) !=NULL ; +} + +static bool usb_generic_driver_match (struct usb_device *udev) +{ +/* +* If any other driver wants the device, leave the device to this other +* driver. +*/ +if (bus_for_each_drv (&usb_bus_type,NULL , udev, __check_usb_generic)) +return false; + +return true; +} +int usb_generic_driver_probe (struct usb_device *udev) {int err, c;
@@ -285,6 +313,7 @@ int usb_generic_driver_resume(struct usb_device *udev, pm_message_t msg)struct usb_device_driver usb_generic_driver = { .name ="usb" , + .match = usb_generic_driver_match, .probe = usb_generic_driver_probe, .disconnect = usb_generic_driver_disconnect, #ifdef CONFIG_PM
linux/usb.h +2 -0
@@ -1237,6 +1237,7 @@ struct usb_driver {struct usb_device_driver {const char *name; +bool (*match) (struct usb_device *udev);int (*probe) (struct usb_device *udev);void (*disconnect) (struct usb_device *udev);
@@ -1244,6 +1245,7 @@ struct usb_device_driver {int (*resume) (struct usb_device *udev,pm_message_t message);const struct attribute_group **dev_groups;struct usbdrv_wrap drvwrap; +const struct usb_device_id *id_table; unsigned int supports_autosuspend:1; unsigned int generic_subclass:1; };
Signature · 1 line
2.21.0
PATCH v3 5/6 USB: Fallback to generic driver when specific driver fails
In reply to Bastien NoceraIf ->probe fails for a device specific driver, ask the driver core to reprobe us, after having flagged the device for the generic driver to be forced.
--- drivers/usb/core/driver.c | 5 ++++- drivers/usb/core/generic.c | 3 +++ include/linux/usb.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-)
usb/core/driver.c +4 -1
@@ -270,7 +270,10 @@ static int usb_probe_device(struct device *dev)return error; error = udriver->probe (udev); -/* TODO: fallback to generic driver in case of error */ +if (error == -ENODEV && udriver != &usb_generic_driver) { + udev->use_generic_driver =1 ; +return -EPROBE_DEFER ; + }return error; }
usb/core/generic.c +3 -0
@@ -213,6 +213,9 @@ static int __check_usb_generic(struct device_driver *drv, void *data)static bool usb_generic_driver_match (struct usb_device *udev) { +if (udev->use_generic_driver) +return true; +/* * If any other driver wants the device, leave the device to this other * driver.
linux/usb.h +1 -0
@@ -708,6 +708,7 @@ struct usb_device {unsigned lpm_disable_count;u16 hub_delay; + unsigned use_generic_driver:1; };#define to_usb_device (d) container_of(d, struct usb_device, dev)
Signature · 1 line
2.21.0
PATCH v3 6/6 USB: Add driver to control USB fast charge for iOS devices
In reply to Bastien NoceraiOS devices will not draw more than 500mA unless instructed to do so. Setting the charge type power supply property to "fast" tells the device to start drawing more power, using the same procedure that official "MFi" chargers would.
--- MAINTAINERS | 6 + drivers/usb/misc/Kconfig | 10 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/apple-mfi-fastcharge.c | 237 ++++++++++++++++++++++++ 4 files changed, 254 insertions(+) create mode 100644 drivers/usb/misc/apple-mfi-fastcharge.c
MAINTAINERS +6 -0
@@ -16728,6 +16728,12 @@ S: Maintained F: Documentation/usb/acm.rst F: drivers/usb/class/cdc-acm.* +USB APPLE MFI FASTCHARGE DRIVER +M: Bastien Nocera <[email protected]> +L: [email protected] +S: Maintained +F: drivers/usb/misc/apple-mfi-fastcharge.c + USB AR5523 WIRELESS DRIVER M: Pontus Fuchs <[email protected]> L: [email protected]
usb/misc/Kconfig +10 -0
@@ -147,6 +147,16 @@ config USB_APPLEDISPLAY Say Y here if you want to control the backlight of Apple Cinema Displays over USB. This driver provides a sysfs interface. +config APPLE_MFI_FASTCHARGE + tristate "Fast charge control for iOS devices" + select POWER_SUPPLY + help + Say Y here if you want to control whether iOS devices will + fast charge from the USB interface, as implemented in "MFi" + chargers. + + It is safe to say M here. + source "drivers/usb/misc/sisusbvga/Kconfig" config USB_LD
usb/misc/Makefile +1 -0
@@ -11,6 +11,7 @@ obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_EZUSB_FX2) += ezusb.o obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o +obj-$(CONFIG_APPLE_MFI_FASTCHARGE) += apple-mfi-fastcharge.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o
usb/misc/apple-mfi-fastcharge.c new file +237 -0
237 lines not on this page · raw message
Signature · 1 line
2.21.0
Hey,
Any updates on getting this into the USB tree?
Alan acked the patchset more than a month ago.
Quoted 5 lines · Bastien Nocera
This is version 3 of the patch set.
Changes in v3:
- Add Alan's ack
- don't exportusb_device_match_id()
Hey,
Quoted 5 lines · Bastien Nocera
Hey,
Any updates on getting this into the USB tree?
Alan acked the patchset more than a month ago.
Thought I'd ask again, the 6 patches were acked by Alan, and tested by me. Is there any chance they could be considered for merging, or reviewed?
Cheers
Quoted 8 lines · Bastien Nocera
Quoted 5 lines
This is version 3 of the patch set.
Changes in v3:
- Add Alan's ack
- don't exportusb_device_match_id()
Greg Kroah-Hartman
maintainerQuoted 5 lines · Bastien Nocera
Hey,
Quoted 2 lines · Bastien Nocera
Hey,
Quoted 7 lines
Quoted 3 lines
Any updates on getting this into the USB tree?
Alan acked the patchset more than a month ago.
Thought I'd ask again, the 6 patches were acked by Alan, and tested by me. Is there any chance they could be considered for merging, or reviewed?
Ugh, sorry, these fell through the cracks. They are still in my "to-review" queue, I'll try to get to them by the end of the week.
thanks,
greg k-h
Quoted 10 lines · Greg Kroah-Hartman
Quoted 9 lines · Bastien Nocera
Hey,
Quoted 5 lines · Bastien Nocera
Hey,
Any updates on getting this into the USB tree?
Alan acked the patchset more than a month ago.
Quoted 7 lines
Quoted 4 lines
Thought I'd ask again, the 6 patches were acked by Alan, and tested by
me. Is there any chance they could be considered for merging, or reviewed?Ugh, sorry, these fell through the cracks. They are still in my "to-review" queue, I'll try to get to them by the end of the week.
No worries, looking forward to the review.
Quoted 10 lines · Greg Kroah-Hartman
Quoted 9 lines · Bastien Nocera
Hey,
Quoted 5 lines · Bastien Nocera
Hey,
Any updates on getting this into the USB tree?
Alan acked the patchset more than a month ago.
Quoted 7 lines
Quoted 4 lines
Thought I'd ask again, the 6 patches were acked by Alan, and tested by
me. Is there any chance they could be considered for merging, or reviewed?Ugh, sorry, these fell through the cracks. They are still in my "to-review" queue, I'll try to get to them by the end of the week.
Hey,
It's been a month, and it missed the last merge window. Is there anything else I should be doing?
Cheers
Greg Kroah-Hartman
maintainerQuoted 16 lines · Bastien Nocera
Quoted 15 lines · Greg Kroah-Hartman
Quoted 13 lines · Bastien Nocera
Hey,
Quoted 5 lines · Bastien Nocera
Hey,
Any updates on getting this into the USB tree?
Alan acked the patchset more than a month ago.
Thought I'd ask again, the 6 patches were acked by Alan, and tested by
me. Is there any chance they could be considered for merging, or reviewed?
Quoted 7 lines
Quoted 2 lines
Ugh, sorry, these fell through the cracks. They are still in my "to-review" queue, I'll try to get to them by the end of the week.
Hey,
It's been a month, and it missed the last merge window. Is there anything else I should be doing?
{sigh} my fault, will look at this today, sorry...
Greg Kroah-Hartman
maintainerQuoted 9 lines · Bastien Nocera
This is version 3 of the patch set.
Changes in v3:
- Add Alan's ack
- don't exportusb_device_match_id()Changes in v2:
- checkpatch.pl is now quiet
- fallback to the generic driver when driver ->probe() fails
Sorry for the long response to this, my fault.
At first, I really don't like the idea of using the usb device driver interface, but I don't think there's a better way. And, you did the work to make it so that it works cleanly, which is always appreciated.
So all now queued up, let's see what breaks in linux-next with it! :)
One note, your patches had to be applied with "-p0" to git, normally we do it with "-p1", I don't know how you generated your patches at 0 depth.
thanks,
greg k-h
Quoted 11 lines · Greg Kroah-Hartman
Quoted 9 lines · Bastien Nocera
This is version 3 of the patch set.
Changes in v3:
- Add Alan's ack
- don't exportusb_device_match_id()Changes in v2:
- checkpatch.pl is now quiet
- fallback to the generic driver when driver ->probe() fails
Quoted 6 lines
Sorry for the long response to this, my fault.
At first, I really don't like the idea of using the usb device driver interface, but I don't think there's a better way. And, you did the work to make it so that it works cleanly, which is always appreciated.
I'm hoping that a few user-space drivers end up upstream in the kernel for hardware that needs it.
Quoted 1 line
So all now queued up, let's see what breaks in linux-next with it! :)
And I sure hope I won't be break anything!
Quoted 4 lines
One note, your patches had to be applied with "-p0" to git, normally we
do it with "-p1", I don't know how you generated your patches at 0 depth.
My fault. I tried to use the "noprefix" git diff option to make it easier to visualise changes, but that leaked into generated patches as well. I've disabled it since.
I plan on making some more changes to the USB subsystem in the (near) future, so it's to get my feet wet with this.
Cheers
Greg Kroah-Hartman
maintainerQuoted 14 lines · Bastien Nocera
Quoted 13 lines · Greg Kroah-Hartman
Quoted 9 lines · Bastien Nocera
This is version 3 of the patch set.
Changes in v3:
- Add Alan's ack
- don't exportusb_device_match_id()Changes in v2:
- checkpatch.pl is now quiet
- fallback to the generic driver when driver ->probe() failsSorry for the long response to this, my fault.
Quoted 7 lines
Quoted 4 lines
At first, I really don't like the idea of using the usb device driver interface, but I don't think there's a better way. And, you did the work to make it so that it works cleanly, which is always appreciated.
I'm hoping that a few user-space drivers end up upstream in the kernel for hardware that needs it.
And here I am wanting to move more USB drivers to userspace :)
What ones do you see that are currently in userspace that should be in the kernel? The power control one here makes sense, are there others like this?
Quoted 2 lines
I plan on making some more changes to the USB subsystem in the (near) future, so it's to get my feet wet with this.
That was a serious modification to "start" with, nice work.
greg k-h
Quoted 26 lines · Greg Kroah-Hartman
Quoted 21 lines · Bastien Nocera
Quoted 11 lines · Greg Kroah-Hartman
Quoted 9 lines · Bastien Nocera
This is version 3 of the patch set.
Changes in v3:
- Add Alan's ack
- don't exportusb_device_match_id()Changes in v2:
- checkpatch.pl is now quiet
- fallback to the generic driver when driver ->probe() failsQuoted 8 lines
Sorry for the long response to this, my fault.
At first, I really don't like the idea of using the usb device driver
interface, but I don't think there's a better way. And, you did the
work to make it so that it works cleanly, which is always appreciated.Quoted 3 lines
I'm hoping that a few user-space drivers end up upstream in the kernel
for hardware that needs it.
Quoted 6 lines
And here I am wanting to move more USB drivers to userspace :)
What ones do you see that are currently in userspace that should be in
the kernel? The power control one here makes sense, are there others like this?
Well, I don't know yet. I would expect them to be of similar ilk, and fit in with the type of devices the kernel already handles but would use interfaces for on other devices.
As I mentioned at the beginning of the discussion, I'm not trying to bring in user-space drivers that don't fit in an existing subsystem, but rather those that are badly designed ;)
Quoted 5 lines
Quoted 3 lines
I plan on making some more changes to the USB subsystem in the (near)
future, so it's to get my feet wet with this.That was a serious modification to "start" with, nice work.
I think what I want to work on, revoke support for USB devices, might be more complicated/racy/full of security problems.