Jack sensing in snd_usb_audio ?

2016-10-11 Thread Bastien Nocera
Hey,

I recently bought some cheap USB soundcards for a computer that doesn't
have any audio output other than through the HDMI output, and the
screen I'm attaching doesn't have an audio output.

So I'm looking to plug in 2 of those USB soundcards, and switch between
them depending on whether I'm using headphones, or want to use the
standalone speaker.

Obviously, it would be so much nicer if I didn't have to switch between
the outputs by hand, and ignored the "headphones" sound card when not
plugged in.

My questions are:
- does the USB audio driver support jack sensing?
- is this something standard that's just not implemented yet? In which
case, I'd be up for at least trying, given specs.
- or is it something that depends on the device, and in which case, how
would I find out?

Some details about the device itself below.

Cheers

/proc/asound/cards:
 4 [Device ]: USB-Audio - USB Audio Device
  GeneralPlus USB Audio Device at usb-:00:14.0-9, full 
speed

$ amixer -c 4
Simple mixer control 'Speaker',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 30
  Mono:
  Front Left: Playback 16 [53%] [-21.00dB] [on]
  Front Right: Playback 16 [53%] [-21.00dB] [on]
Simple mixer control 'Mic',0
  Capabilities: pvolume pvolume-joined cvolume cvolume-joined pswitch
pswitch-joined cswitch cswitch-joined
  Playback channels: Mono
  Capture channels: Mono
  Limits: Playback 0 - 14 Capture 0 - 30
  Mono: Playback 1 [7%] [-10.50dB] [off] Capture 26 [87%] [27.00dB]
[on]
Simple mixer control 'Auto Gain Control',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [off]
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Jack sensing in snd_usb_audio ?

2016-10-12 Thread Bastien Nocera
On Wed, 2016-10-12 at 11:14 +0200, Felipe Ferreri Tonello wrote:
> 

> What you need is PulseAudio server instead. PulseAudio supports this
> via
> kcontrol for quite some time.
> 
> Jack is supposed to be a low-latency audio server for audio
> applications, not for normal desktop usage.

I'm not talking about jackd but about jack sensing.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Jack sensing in snd_usb_audio ?

2016-10-12 Thread Bastien Nocera
On Wed, 2016-10-12 at 19:36 +0900, Takashi Sakamoto wrote:
> On Oct 12 2016 14:10, Bastien Nocera wrote:
> > My questions are:
> > - does the USB audio driver support jack sensing?
> > - is this something standard that's just not implemented yet? In
> > which
> > case, I'd be up for at least trying, given specs.
> > - or is it something that depends on the device, and in which case,
> > how
> > would I find out?
> 
> 
> In ALSA usb-related codes, there's no functions calls for
> snd_jack_*(),
> thus none of ALSA drivers for USB support Jack sense feature of ALSA
> control interface.
> 
> The requirement of Jack sense feature is whether hardwares support
> it.
> For example, some hardware codecs such as HDA codecs generates
> signals
> when plugs are insert to jacks connected to the codecs. Corresponding
> ALSA drivers catch the signals, then tell it to user land.
> 
> If your hardware performs like it, you have a probability to add
> support
> for jack sense feature to ALSA drivers for USB. But I don't know
> exactly
> that USB related specifications such as USB Audio Device Class
> 1.0/2.0/3.0 supports the feature.

Looks like whether or not jack sensing works depends on the device
itself, but there is a mechanism to propagate the change in setup in
the USB Audio 2.0 spec, in the "Interrupts" section:
"
A change of state in the audio function is most often caused by a
certain event that takes place. An event can either be user-initiated
or device-initiated. User-initiated jack insertion or removal is a
typical example of a user-initiated event.
"

I guess I should probably test in another operating system to check
whether the hardware I have supports this to start with, and go from
there.

Cheers
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [alsa-devel] Jack sensing in snd_usb_audio ?

2016-10-12 Thread Bastien Nocera
On Wed, 2016-10-12 at 14:43 +0200, Clemens Ladisch wrote:
> Bastien Nocera wrote:
> > Looks like whether or not jack sensing works depends on the device
> > itself, but there is a mechanism to propagate the change in setup
> > in
> > the USB Audio 2.0 spec
> 
> 
> Some recent Windows 10 beta added partial support for USB Audio 2.0.
> Earlier Windowses implement only USB Audio 1.0, which does not
> mention
> jacks.
> 
> > "
> > A change of state in the audio function is most often caused by a
> > certain event that takes place. An event can either be user-
> > initiated
> > or device-initiated. User-initiated jack insertion or removal is a
> > typical example of a user-initiated event.
> > "
> 
> 
> There are not many USB Audio 2.0 devices, and I'm not aware of any
> that actually implements this.

I guess I would see whether there are events if I captured the USB
traffic even without special handling/turning on a feature in the
drivers, right?
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [alsa-devel] Jack sensing in snd_usb_audio ?

2016-10-12 Thread Bastien Nocera
On Wed, 2016-10-12 at 18:06 +0200, Clemens Ladisch wrote:
> Bastien Nocera wrote:
> > On Wed, 2016-10-12 at 14:43 +0200, Clemens Ladisch wrote:
> > > Bastien Nocera wrote:
> > > > "
> > > > A change of state in the audio function is most often caused by
> > > > a
> > > > certain event that takes place. An event can either be user-
> > > > initiated
> > > > or device-initiated. User-initiated jack insertion or removal
> > > > is a
> > > > typical example of a user-initiated event.
> > > > "
> > > 
> > > 
> > > There are not many USB Audio 2.0 devices, and I'm not aware of
> > > any
> > > that actually implements this.
> > 
> > 
> > I guess I would see whether there are events if I captured the USB
> > traffic even without special handling/turning on a feature in the
> > drivers, right?
> 
> 
> Most devices do not even have the status endpoint (see "lsusb -v").
> To check what events arrive, you can add logging to the
> snd_usb_mixer_interrupt() function.

I'm guessing it doesn't support it then (see attached log)

I also checked the input device output when plugging in something, with
evtest, and no feedback either.
Bus 003 Device 035: ID 1b3f:2008 Generalplus Technology Inc. 
Device Descriptor:
  bLength18
  bDescriptorType 1
  bcdUSB   1.10
  bDeviceClass0 
  bDeviceSubClass 0 
  bDeviceProtocol 0 
  bMaxPacketSize0 8
  idVendor   0x1b3f Generalplus Technology Inc.
  idProduct  0x2008 
  bcdDevice1.00
  iManufacturer   1 GeneralPlus
  iProduct2 USB Audio Device
  iSerial 0 
  bNumConfigurations  1
  Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength  253
bNumInterfaces  4
bConfigurationValue 1
iConfiguration  0 
bmAttributes 0x80
  (Bus Powered)
MaxPower  100mA
Interface Descriptor:
  bLength 9
  bDescriptorType 4
  bInterfaceNumber0
  bAlternateSetting   0
  bNumEndpoints   0
  bInterfaceClass 1 Audio
  bInterfaceSubClass  1 Control Device
  bInterfaceProtocol  0 
  iInterface  0 
  AudioControl Interface Descriptor:
bLength10
bDescriptorType36
bDescriptorSubtype  1 (HEADER)
bcdADC   1.00
wTotalLength  100
bInCollection   2
baInterfaceNr( 0)   1
baInterfaceNr( 1)   2
  AudioControl Interface Descriptor:
bLength12
bDescriptorType36
bDescriptorSubtype  2 (INPUT_TERMINAL)
bTerminalID 1
wTerminalType  0x0101 USB Streaming
bAssocTerminal  0
bNrChannels 2
wChannelConfig 0x0003
  Left Front (L)
  Right Front (R)
iChannelNames   0 
iTerminal   0 
  AudioControl Interface Descriptor:
bLength12
bDescriptorType36
bDescriptorSubtype  2 (INPUT_TERMINAL)
bTerminalID 4
wTerminalType  0x0201 Microphone
bAssocTerminal  0
bNrChannels 1
wChannelConfig 0x0001
  Left Front (L)
iChannelNames   0 
iTerminal   0 
  AudioControl Interface Descriptor:
bLength 9
bDescriptorType36
bDescriptorSubtype  3 (OUTPUT_TERMINAL)
bTerminalID 3
wTerminalType  0x0301 Speaker
bAssocTerminal  0
bSourceID   6
iTerminal   0 
  AudioControl Interface Descriptor:
bLength 9
bDescriptorType36
bDescriptorSubtype  3 (OUTPUT_TERMINAL)
bTerminalID 2
wTerminalType  0x0101 USB Streaming
bAssocTerminal  0
bSourceID   9
iTerminal   0 
  AudioControl Interface Descriptor:
bLength 7
bDescriptorType36
bDescriptorSubtype  5 (SELECTOR_UNIT)
bUnitID 9
bNrInPins   1
baSource( 0)5
iSelector   0 
  AudioControl Interface Descriptor:
bLength10
bDescriptorType36
bDescriptorSubtype  6 (FEATURE_UNIT)
bUnitID 6
bSourceID   8
bCo

Re: [alsa-devel] Jack sensing in snd_usb_audio ?

2016-10-28 Thread Bastien Nocera
On Tue, 2016-10-18 at 14:07 +0200, Takashi Iwai wrote:
> On Wed, 12 Oct 2016 18:15:04 +0200,
> Bastien Nocera wrote:
> > 
> > On Wed, 2016-10-12 at 18:06 +0200, Clemens Ladisch wrote:
> > > Bastien Nocera wrote:
> > > > On Wed, 2016-10-12 at 14:43 +0200, Clemens Ladisch wrote:
> > > > > Bastien Nocera wrote:
> > > > > > "
> > > > > > A change of state in the audio function is most often
> > > > > > caused by
> > > > > > a
> > > > > > certain event that takes place. An event can either be
> > > > > > user-
> > > > > > initiated
> > > > > > or device-initiated. User-initiated jack insertion or
> > > > > > removal
> > > > > > is a
> > > > > > typical example of a user-initiated event.
> > > > > > "
> > > > > 
> > > > > 
> > > > > There are not many USB Audio 2.0 devices, and I'm not aware
> > > > > of
> > > > > any
> > > > > that actually implements this.
> > > > 
> > > > 
> > > > I guess I would see whether there are events if I captured the
> > > > USB
> > > > traffic even without special handling/turning on a feature in
> > > > the
> > > > drivers, right?
> > > 
> > > 
> > > Most devices do not even have the status endpoint (see "lsusb
> > > -v").
> > > To check what events arrive, you can add logging to the
> > > snd_usb_mixer_interrupt() function.
> > 
> > I'm guessing it doesn't support it then (see attached log)
> 
> So this looks like a HID, not from the audio device class.
> It's an oft-seen implementation.
> 
> > I also checked the input device output when plugging in something,
> > with
> > evtest, and no feedback either.
> 
> Then at first you need to hack a HID driver to support this device.
> It'll create an input device, and then we'll need to find some way to
> couple the given input device and the audio device.  We can parse the
> sysfs device path to figure out, but I'm not sure what's the best way
> to tell it to applications.

You misunderstood. There's no input events on the input device, there's
also no hidraw events (hid-recorder didn't see any events) and using
usbmon also got me no USB events whatsoever when plugging or unplugging
a jack on either the headphones or the microphone jack.

So there's really nothing that we can do for this hardware. Shame, it
would have been pretty useful to me :)

Thanks all for your help
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] HID: Use multitouch driver for Type Covers

2015-12-14 Thread Bastien Nocera
On Mon, 2015-12-14 at 21:50 +0900, Akihiko Odaki wrote:
> Use multitouch driver instead of microsoft one for Microsoft Surface
> Type Covers.
> 
> By using MT_CLS_EXPORT_ALL_INPUTS, the keyboards function as well as
> the multitouch pads do.

I've discussed this a couple of weeks back with Benjamin Tissoires, and
this patch would break the special keys (mute, brightness up/down,
keyboard backlight up/down and play/pause).

The recommended way to fix this was to move multi-touch processing into
the Microsoft driver, so that it would handle the trackpad's multi-
touch events.

You should be able to do this by carefully picking up the handling code
from hid-multitouch, or do something similar to what's done in hid-
wacom, which has the same problem as the Type Cover handling.

Can you confirm that this does indeed break those special keys? If it
does, it's a NAK from my side.

Cheers
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] HID: Use multitouch driver for Type Covers

2015-12-18 Thread Bastien Nocera
On Mon, 2015-12-14 at 21:50 +0900, Akihiko Odaki wrote:
> Use multitouch driver instead of microsoft one for Microsoft Surface
> Type Covers.
> 
> By using MT_CLS_EXPORT_ALL_INPUTS, the keyboards function as well as
> the multitouch pads do.
> 
> Signed-off-by: Akihiko Odaki 

All the multimedia keys work, and MT support also works, on my Surface
3 cover (045e:07de).

*But* the Caps-Lock key's LED doesn't light up anymore. Can you verify
it does on yours as well?

Cheers
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] HID: Use multitouch driver for Type Covers

2016-04-05 Thread Bastien Nocera
On Sat, 2015-12-19 at 10:34 +0900, Akihiko Odaki wrote:
> No, it doesn't work.

According to:
https://github.com/jimdigriz/debian-mssp4

Running "kbd_mode -u" afterwards would fix the Caps-Lock key not
working. I have no idea what the wider consequence of this would be
though[1].

Anything we can do in the kernel to have that working by default?

[1]: kbd_mode calls ioctl(fd, KDSKBMODE, K_UNICODE) with fd being the
console's fd.

> On 12/19/2015 12:06 AM, Bastien Nocera wrote:
> > 
> > On Mon, 2015-12-14 at 21:50 +0900, Akihiko Odaki wrote:
> > > 
> > > Use multitouch driver instead of microsoft one for Microsoft
> > > Surface
> > > Type Covers.
> > > 
> > > By using MT_CLS_EXPORT_ALL_INPUTS, the keyboards function as well
> > > as
> > > the multitouch pads do.
> > > 
> > > Signed-off-by: Akihiko Odaki 
> > All the multimedia keys work, and MT support also works, on my
> > Surface
> > 3 cover (045e:07de).
> > 
> > *But* the Caps-Lock key's LED doesn't light up anymore. Can you
> > verify
> > it does on yours as well?
> > 
> > Cheers
> > 
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Running ADB on a "stock" distribution (g_ffs)

2015-05-20 Thread Bastien Nocera
Hey,

After discussing this with Andrzej, I'm no closer to being able to get
this working...

I'm trying to run adbd (the service that would usually run on an
Android phone in developer mode) on a stock distribution, on a device
that used to run Windows 8 (and now a Fedora).

This is my version of adbd:
https://github.com/hadess/adbd/

This is the systemd service file I eventually want to use, but I'm
running those commands "by hand" right now, and they fail in the same
way.

https://github.com/hadess/adbd/blob/master/adbd.service

I'm getting this error from adbd:
OPENING /dev/usb-ffs/adb/ep0 [ /dev/usb-ffs/adb/ep0: writing strings failed: 
errno=16]

Which comes from this error message:
https://github.com/hadess/adbd/blob/master/adb/usb_linux_client.c#L275

It looks like this can only happen if the gadget FS was already registered:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/gadget/legacy/g_ffs.c#n301

Any ideas?

Cheers
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Running ADB on a "stock" distribution (g_ffs)

2015-05-21 Thread Bastien Nocera
On Thu, 2015-05-21 at 08:42 +0200, Krzysztof Opasiak wrote:
> On 05/20/2015 06:42 PM, Bastien Nocera wrote:
> > Hey,
> > 
> > After discussing this with Andrzej, I'm no closer to being able to 
> > get
> > this working...
> > 
> > I'm trying to run adbd (the service that would usually run on an
> > Android phone in developer mode) on a stock distribution, on a 
> > device
> > that used to run Windows 8 (and now a Fedora).
> > 
> > This is my version of adbd:
> > https://github.com/hadess/adbd/
> > 
> > This is the systemd service file I eventually want to use, but I'm
> > running those commands "by hand" right now, and they fail in the 
> > same
> > way.
> > 
> > https://github.com/hadess/adbd/blob/master/adbd.service
> > 
> > I'm getting this error from adbd:
> > OPENING /dev/usb-ffs/adb/ep0 [ /dev/usb-ffs/adb/ep0: writing 
> > strings failed: errno=16]

Using ffs-test from tools/usb/ffs-test.c I have the same problem.
Writing descriptors works, but writing strings throws -EBUSY.

Those are the options used (from /boot/config-4.1.0
-0.rc0.git13.2.fc22.i686)
CONFIG_USB_GADGET=m
CONFIG_USB_FUNCTIONFS_GENERIC=y
CONFIG_USB_GADGET_VBUS_DRAW=2
CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
CONFIG_USB_LIBCOMPOSITE=m
CONFIG_USB_F_ACM=m
CONFIG_USB_U_SERIAL=m
CONFIG_USB_F_SERIAL=m
CONFIG_USB_F_OBEX=m
CONFIG_USB_F_FS=m
CONFIG_USB_CONFIGFS=m
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_FUNCTIONFS=m
CONFIG_USB_FUNCTIONFS_GENERIC=y
CONFIG_USB_G_SERIAL=m

> > Which comes from this error message:
> > https://github.com/hadess/adbd/blob/master/adb/usb_linux_client.c#L
> > 275
> > 
> > It looks like this can only happen if the gadget FS was already 
> > registered:
> > https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tre
> > e/drivers/usb/gadget/legacy/g_ffs.c#n301
> > 
> > Any ideas?
> > 
> 
> Could you please try to use ConfigFS interface instead of using 
> g_ffs?

Could you explain how I would set that up? Is that the way:
http://www.spinics.net/lists/linux-usb/msg96121.html
?

> I have used this setup some time ago and it worked fine, so it 
> should be 
> a good method of checking if adbd is working properly.
> 
> (tools/usb/ffs-aio-example) with g_ffs instead of adbd and see what 
> happen.

ffs-test fails in the same way, as mentioned above.

Does one need specific hardware to make this work? This is a tablet,
so I usually use a USB OTG adapter to plug in keyboard/mouse/network,
but I unplug all this to run the test tool, or adbd.

> BTW.
> Which kernel version do you use?

I'm still on Linus' 4.1.0-rc0, but if anything relevant changed, I can
certainly update to a newer version.

Cheers
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Running ADB on a "stock" distribution (g_ffs)

2015-05-21 Thread Bastien Nocera
On Thu, 2015-05-21 at 09:38 +0200, Krzysztof Opasiak wrote:
> On 05/21/2015 09:18 AM, Bastien Nocera wrote:
> > 

> > Does one need specific hardware to make this work? This is a 
> > tablet,
> > so I usually use a USB OTG adapter to plug in 
> > keyboard/mouse/network,
> > but I unplug all this to run the test tool, or adbd.
> > 
> 
> Nope. hardware is being automatically selected (we simply take first 
> free udc or return -ENODEV if no free udc).
> 
> You may check if you have an UDC in your system (check if 
> /sys/class/udc 
> dir is not empty)

Huh. It there, but it *is* empty on that tablet.

But my config says:
# CONFIG_USB_BDC_UDC is not set

I guess I should turn that on, right?
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Running ADB on a "stock" distribution (g_ffs)

2015-05-21 Thread Bastien Nocera
On Thu, 2015-05-21 at 09:50 +0200, Bastien Nocera wrote:
> On Thu, 2015-05-21 at 09:38 +0200, Krzysztof Opasiak wrote:
> > On 05/21/2015 09:18 AM, Bastien Nocera wrote:
> > > 
> 
> > > Does one need specific hardware to make this work? This is a 
> > > tablet,
> > > so I usually use a USB OTG adapter to plug in 
> > > keyboard/mouse/network,
> > > but I unplug all this to run the test tool, or adbd.
> > > 
> > 
> > Nope. hardware is being automatically selected (we simply take 
> > first 
> > free udc or return -ENODEV if no free udc).
> > 
> > You may check if you have an UDC in your system (check if 
> > /sys/class/udc 
> > dir is not empty)
> 
> Huh. It there, but it *is* empty on that tablet.
> 
> But my config says:
> # CONFIG_USB_BDC_UDC is not set
> 
> I guess I should turn that on, right?

Should have read the Kconfig, that's for:
"Broadcom USB3.0 device controller IP driver(BDC)"

So not what I'm looking for.

But this is a Bay Trail tablet, so unless the firmware is doing stupid
things, the functionality should surely be available, as Android runs
on some of that SoC.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Running ADB on a "stock" distribution (g_ffs)

2015-05-21 Thread Bastien Nocera
On Thu, 2015-05-21 at 10:09 +0200, Krzysztof Opasiak wrote:
> Could you specify exactly the model?

Onda v975w

> If android is running fine on it you may check android kernel config 
> for 
> this device and check which udc is enabled.

No kernel sources from this Chinese vendor. But it looks like the
USB_DWC3 config is the one to enable.

In the meantime, shouldn't the ffs-test and adbd have failed with
ENOTSUPP instead of EBUSY if no hardware support was available?
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Running ADB on a "stock" distribution (g_ffs)

2015-05-21 Thread Bastien Nocera
On Thu, 2015-05-21 at 11:08 +0200, Krzysztof Opasiak wrote:
> On 05/21/2015 10:39 AM, Bastien Nocera wrote:
> > On Thu, 2015-05-21 at 10:09 +0200, Krzysztof Opasiak wrote:
> > > Could you specify exactly the model?
> > 
> > Onda v975w
> > 
> > > If android is running fine on it you may check android kernel 
> > > config
> > > for
> > > this device and check which udc is enabled.
> > 
> > No kernel sources from this Chinese vendor. But it looks like the
> > USB_DWC3 config is the one to enable.
> > 
> 
> I see that this tablet is running windows by default so just flash 
> it 
> with stock image and  check what device manager says about udc;)

The Baytrail UDC driver is supposed to be a DWC3 PCI device, but it
doesn't show up in lspci at all. Given that I managed to make an NFC
chip show up that I didn't know was in the machine, I guess it's
possibly hidden in the firmware somewhere.

> > In the meantime, shouldn't the ffs-test and adbd have failed with
> > ENOTSUPP instead of EBUSY if no hardware support was available?
> > 
> 
> As far as I understand the code it should fail with -ENODEV and 
> debug 
> message:
> 
> pr_debug("couldn't find an available UDC\n");

I get that stack trace when writing is attempted:
[  122.362269] [ cut here ]
[  122.362287] WARNING: CPU: 2 PID: 2384 at 
drivers/usb/gadget/function/f_fs.c:3417 ffs_ep0_write+0x730/0x810 [usb_f_fs]()
[  122.362292] Modules linked in: g_ffs usb_f_fs libcomposite udc_core bnep 
bluetooth fuse hid_logitech_hidpp uvcvideo videobuf2_vmalloc snd_usb_audio 
videobuf2_core videobuf2_memops v4l2_common snd_usbmidi_lib videodev snd_hwdep 
snd_rawmidi media hid_multitouch hid_logitech_dj nf_conntrack_netbios_ns 
nf_conntrack_broadcast ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_conntrack 
ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat 
nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security 
ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 
nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security 
iptable_raw vfat pn544_mei fat mei_phy pn544 intel_rapl hci 
intel_soc_dts_thermal coretemp nfc gpio_keys snd_soc_sst_baytrail_pcm
[  122.362412]  kvm_intel iTCO_wdt snd_soc_sst_ipc iTCO_vendor_support 
snd_soc_sst_dsp kvm snd_soc_sst_byt_rt5640_mach crc32_pclmul crc32c_intel 
snd_intel_sst_acpi snd_intel_sst_core snd_soc_sst_mfld_platform snd_soc_rt5640 
snd_soc_rl6231 snd_soc_core snd_compress snd_pcm_dmaengine tpm_crb snd_seq tpm 
dw_dmac int3402_thermal dw_dmac_core snd_seq_device int3400_thermal kxcjk_1013 
soc_button_array snd_pcm processor_thermal_device int3403_thermal 
acpi_thermal_rel int340x_thermal_zone mei_txe industrialio_triggered_buffer 
goodix mei snd_timer lpc_ich ac i2c_hid kfifo_buf acpi_pad dell_smo8800 
iosf_mbi industrialio snd soundcore pwm_lpss_platform rfkill_gpio battery 
regmap_i2c pwm_lpss i2c_designware_platform rfkill snd_soc_sst_acpi 
i2c_designware_core nfsd auth_rpcgss nfs_acl lockd grace sunrpc dm9601 usbnet
[  122.362529]  mii i915 mmc_block i2c_algo_bit drm_kms_helper drm video 
sdhci_acpi sdhci mmc_core
[  122.362555] CPU: 2 PID: 2384 Comm: adbd Tainted: GW   
4.1.0-0.rc4.git0.1.1.fc22.i686 #1
[  122.362561] Hardware name: To be filled by O.E.M. To be filled by 
O.E.M./Aptio CRB, BIOS 5.6.5 07/25/2014
[  122.362567]  c0d1f947 415badfa  d1029e64 c0a86e54  d1029e94 
c045b937
[  122.362584]  c0c37f94 0002 0950 f9b313d4 0d59 f9b2ebf0 f9b2ebf0 
fff0
[  122.362600]  0003 deb53d00 d1029ea4 c045ba42 0009  d1029f08 
f9b2ebf0
[  122.362617] Call Trace:
[  122.362633]  [] dump_stack+0x41/0x52
[  122.362645]  [] warn_slowpath_common+0x87/0xc0
[  122.362658]  [] ? ffs_ep0_write+0x730/0x810 [usb_f_fs]
[  122.362668]  [] ? ffs_ep0_write+0x730/0x810 [usb_f_fs]
[  122.362678]  [] warn_slowpath_null+0x22/0x30
[  122.362689]  [] ffs_ep0_write+0x730/0x810 [usb_f_fs]
[  122.362702]  [] ? ffs_ep0_read+0x380/0x380 [usb_f_fs]
[  122.362712]  [] __vfs_write+0x2f/0x100
[  122.362722]  [] ? __sb_start_write+0x52/0x110
[  122.362731]  [] vfs_write+0x94/0x1b0
[  122.362740]  [] ? mutex_lock+0x10/0x30
[  122.362749]  [] SyS_write+0x51/0xb0
[  122.362759]  [] sysenter_do_call+0x12/0x12
[  122.362766] ---[ end trace 0673d3467cecf8db ]---

> Have you tried loading other gadget modules?

No, I didn't try.

>  If not, maybe try to load 
> g_ether and check what dmesg says.

I didn't have g_ether built, so tried with g_serial:
# modprobe g_serial 
modprobe: ERROR: could not insert 'g_serial': No such device

Cheers
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: Running ADB on a "stock" distribution (g_ffs)

2015-05-21 Thread Bastien Nocera
On Thu, 2015-05-21 at 19:08 +0200, Marcel Holtmann wrote:
> Hi Bastien,
> 
> > > > > Could you specify exactly the model?
> > > > 
> > > > Onda v975w
> > > > 
> > > > > If android is running fine on it you may check android 
> > > > > kernel 
> > > > > config
> > > > > for
> > > > > this device and check which udc is enabled.
> > > > 
> > > > No kernel sources from this Chinese vendor. But it looks like 
> > > > the
> > > > USB_DWC3 config is the one to enable.
> > > > 
> > > 
> > > I see that this tablet is running windows by default so just 
> > > flash 
> > > it 
> > > with stock image and  check what device manager says about udc;)
> > 
> > The Baytrail UDC driver is supposed to be a DWC3 PCI device, but it
> > doesn't show up in lspci at all. Given that I managed to make an 
> > NFC
> > chip show up that I didn't know was in the machine, I guess it's
> > possibly hidden in the firmware somewhere.
> 
> not all devices enumerate via PCI. Some of them only enumerate via 
> ACPI.

Right, but the UDC support for Bay Trail is only currently supported
on Linux through PCI, no?

If it's supported any other way, would you know the ACPI ID for it? I
couldn't find anything browsing through the device's DSDT. Given that
the v975i variant of the device runs on Android (and this version can
run on Android, I think), the device is bound to be exported in some
way.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 0/3] Proposal for making hid_have_special_driver obsolete

2017-06-14 Thread Bastien Nocera


> On 14 Jun 2017, at 10:24, Benjamin Tissoires  
> wrote:
> 
> Hi,
> 
> As mentioned by Jiri, I found a way to have this horrible list a thing from
> the past (to some extends).
> 
> The basic observation is that now, since v4.12, hid-generic should not be an
> issue for any device, given that all it does is parsing the report descriptor
> and starting the IRQs/URBs.
> 
> So it should not be an issue to have hid-generic handling all incoming devices
> until the specialized driver comes in and replace it.
> 
> For users, that means that they will see an input node appearing and
> disappearing as soon as hid-XXX.ko gets loaded.

That's way ugly, and slower, when a "multi" quirk is used.

> I have tested this on the Logitech Unifying Receiver and some Wacom devices,
> and all seem happy with the situation.
> 
> Patches 1 and 2 are HID cleanup and something I wanted to put in from a long
> time.
> 
> Patch 3 is the one that does the magic and where I need input from the drivers
> specialists.
> 
> To make things easier to handle, I deported the logic of unbinding hid-generic
> into hid-generic itself. I would think a bus_notifier would be better than
> instrumenting struct hid_driver for drivers (un)registering on the bus, but
> we are missing those events in bus_notifiers.
> Would such events (BUS_NOTIFY_ADD_DRIVER, BUS_NOTIFY_REMOVED_DRIVER) make 
> sense
> outside of this particular case?
> 
> The second question I have is whether or not I need locks around the unbinding
> magic in hid-generic. After a lot of thinking I believe I don't, but I'd 
> prefer
> having a second pair of eyes on this.
> 
> Jiri, this series is on top of a merge of your for-next and your other
> for-4.12/driver-matching-fix branch. I'll resubmit a proper patch that will
> apply properly to for-next as soon as for-4.12/driver-matching-fix gets 
> merged.
> 
> Cheers,
> Benjamin
> 
> Benjamin Tissoires (3):
>  HID: core: move the dynamic quirks handling in core
>  HID: quirks: move the list of special devices into a quirk
>  HID: core: remove the absolute need of hid_have_special_driver[]
> 
> drivers/hid/Makefile|2 +-
> drivers/hid/hid-core.c  |  918 ++---
> drivers/hid/hid-generic.c   |   68 ++-
> drivers/hid/hid-quirks.c| 1236 +++
> drivers/hid/usbhid/Makefile |2 +-
> drivers/hid/usbhid/hid-core.c   |   10 +-
> drivers/hid/usbhid/hid-quirks.c |  399 -
> include/linux/hid.h |   19 +-
> net/bluetooth/hidp/core.c   |2 +-
> 9 files changed, 1380 insertions(+), 1276 deletions(-)
> create mode 100644 drivers/hid/hid-quirks.c
> delete mode 100644 drivers/hid/usbhid/hid-quirks.c
> 
> -- 
> 2.9.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] USB: rio500: Remove Rio 500 kernel driver

2019-09-23 Thread Bastien Nocera
The Rio500 kernel driver has not been used by Rio500 owners since 2001
not long after the rio500 project added support for a user-space USB stack
through the very first versions of usbdevfs and then libusb.

Support for the kernel driver was removed from the upstream utilities
in 2008:
https://gitlab.freedesktop.org/hadess/rio500/commit/943f624ab721eb8281c287650fcc9e2026f6f5db

Cc: Cesar Miquel 
Signed-off-by: Bastien Nocera 
---
 Documentation/usb/rio.rst  | 109 --
 MAINTAINERS|   7 -
 arch/arm/configs/badge4_defconfig  |   1 -
 arch/arm/configs/corgi_defconfig   |   1 -
 arch/arm/configs/pxa_defconfig |   1 -
 arch/arm/configs/s3c2410_defconfig |   1 -
 arch/arm/configs/spitz_defconfig   |   1 -
 arch/mips/configs/mtx1_defconfig   |   1 -
 arch/mips/configs/rm200_defconfig  |   1 -
 drivers/usb/misc/Kconfig   |  10 -
 drivers/usb/misc/Makefile  |   1 -
 drivers/usb/misc/rio500.c  | 554 -
 drivers/usb/misc/rio500_usb.h  |  20 --
 13 files changed, 708 deletions(-)
 delete mode 100644 Documentation/usb/rio.rst
 delete mode 100644 drivers/usb/misc/rio500.c
 delete mode 100644 drivers/usb/misc/rio500_usb.h

diff --git a/Documentation/usb/rio.rst b/Documentation/usb/rio.rst
deleted file mode 100644
index ea73475471db..
--- a/Documentation/usb/rio.rst
+++ /dev/null
@@ -1,109 +0,0 @@
-
-Diamonds Rio
-
-
-Copyright (C) 1999, 2000 Bruce Tenison
-
-Portions Copyright (C) 1999, 2000 David Nelson
-
-Thanks to David Nelson for guidance and the usage of the scanner.txt
-and scanner.c files to model our driver and this informative file.
-
-Mar. 2, 2000
-
-Changes
-===
-
-- Initial Revision
-
-
-Overview
-
-
-This README will address issues regarding how to configure the kernel
-to access a RIO 500 mp3 player.
-Before I explain how to use this to access the Rio500 please be warned:
-
-.. warning::
-
-   Please note that this software is still under development.  The authors
-   are in no way responsible for any damage that may occur, no matter how
-   inconsequential.
-
-It seems that the Rio has a problem when sending .mp3 with low batteries.
-I suggest when the batteries are low and you want to transfer stuff that you
-replace it with a fresh one. In my case, what happened is I lost two 16kb
-blocks (they are no longer usable to store information to it). But I don't
-know if that's normal or not; it could simply be a problem with the flash
-memory.
-
-In an extreme case, I left my Rio playing overnight and the batteries wore
-down to nothing and appear to have corrupted the flash memory. My RIO
-needed to be replaced as a result.  Diamond tech support is aware of the
-problem.  Do NOT allow your batteries to wear down to nothing before
-changing them.  It appears RIO 500 firmware does not handle low battery
-power well at all.
-
-On systems with OHCI controllers, the kernel OHCI code appears to have
-power on problems with some chipsets.  If you are having problems
-connecting to your RIO 500, try turning it on first and then plugging it
-into the USB cable.
-
-Contact Information

-
-   The main page for the project is hosted at sourceforge.net in the following
-   URL: <http://rio500.sourceforge.net>;. You can also go to the project's
-   sourceforge home page at: <http://sourceforge.net/projects/rio500/>;.
-   There is also a mailing list: rio500-us...@lists.sourceforge.net
-
-Authors

-
-Most of the code was written by Cesar Miquel . Keith
-Clayton  is incharge of the PPC port and making sure
-things work there. Bruce Tenison  is adding support
-for .fon files and also does testing. The program will mostly sure be
-re-written and Pete Ikusz along with the rest will re-design it. I would
-also like to thank Tri Nguyen  who provided use
-with some important information regarding the communication with the Rio.
-
-Additional Information and userspace tools
-
-   http://rio500.sourceforge.net/
-
-
-Requirements
-
-
-A host with a USB port running a Linux kernel with RIO 500 support enabled.
-
-The driver is a module called rio500, which should be automatically loaded
-as you plug in your device. If that fails you can manually load it with
-
-  modprobe rio500
-
-Udev should automatically create a device node as soon as plug in your device.
-If that fails, you can manually add a device for the USB rio500::
-
-  mknod /dev/usb/rio500 c 180 64
-
-In that case, set appropriate permissions for /dev/usb/rio500 (don't forget
-about group and world permissions).  Both read and write permissions are
-required for proper operation.
-
-That's it.  The Rio500 Utils at: http://rio500.sourceforge.net should
-be able to access the rio500.
-
-Limits
-==
-
-You can use only a single rio500 device at a time with your computer.
-
-Bugs
-
-
-If you encounter any problems feel free to drop me an email.
-
-B

Driver for something that's neither a device nor an interface driver?

2019-09-27 Thread Bastien Nocera
Hey,

I'm trying to write a "power supply" class driver for Apple MFi
devices, and struggling a little with the USB drivers.

To ask many Apple devices to draw more power, we need to make a call to
the device using a vendor command. It doesn't go to an interface, but
to the device itself.

The call done in the kernel would look something like:
usb_control_msg(mfi->udev, usb_sndctrlpipe(mfi->udev, 0), 
0x40, /* Vendor-defined USB get enabled capabilities request. */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
current_ma, /* wValue, current offset */
current_ma, /* wIndex, current offset */
NULL, 0, USB_CTRL_GET_TIMEOUT);

But I can't figure out what type of driver I'd need to just be able to
export that power_supply interface.

Trying to use a "struct usb_device_driver" didn't work as probe
functions were never called, and a "struct usb_driver" gets unbound
after user-space and the ipheth drivers comes around.

This is my "struct usb_driver" attempt:
https://github.com/hadess/apple-mfi-fastcharge

Any ideas what type of driver, or what trick I should be using here?

Cheers



Re: Driver for something that's neither a device nor an interface driver?

2019-09-27 Thread Bastien Nocera
On Fri, 2019-09-27 at 19:38 +0200, Greg KH wrote:
> What does the usb descriptors for the device look like?  Is it only
> the
> "default" control endpoint and no interfaces?  What does the output
> of
> 'usbdevices' show for the device?

The device in question can be an iPhone, an iPod Classic/Nano, or an
iPad, amongst others, and they usually have useful interfaces, such as
mass storage for the older ones, or ethernet, PTP, etc.

> Normally you just bind to the "default" interface for the device, and
> all is good, there should be a few other drivers in the tree that do
> this, but I can't think of one off the top of my head at the moment.

All the interfaces (in the different configurations) are used for
something in the case of the iPhone 6S I'm trying to use.

I've attached the output of "lsusb -v" for the device below.

Bus 003 Device 010: ID 05ac:12a8 Apple, Inc. iPhone5/5C/5S/6
Device Descriptor:
  bLength18
  bDescriptorType 1
  bcdUSB   2.00
  bDeviceClass0 
  bDeviceSubClass 0 
  bDeviceProtocol 0 
  bMaxPacketSize064
  idVendor   0x05ac Apple, Inc.
  idProduct  0x12a8 iPhone5/5C/5S/6
  bcdDevice8.01
  iManufacturer   1 Apple Inc.
  iProduct2 iPhone
  iSerial 3
  bNumConfigurations  4
  Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength   0x0027
bNumInterfaces  1
bConfigurationValue 1
iConfiguration  5 PTP
bmAttributes 0xc0
  Self Powered
MaxPower  500mA
Interface Descriptor:
  bLength 9
  bDescriptorType 4
  bInterfaceNumber0
  bAlternateSetting   0
  bNumEndpoints   3
  bInterfaceClass 6 Imaging
  bInterfaceSubClass  1 Still Image Capture
  bInterfaceProtocol  1 Picture Transfer Protocol (PIMA 15470)
  iInterface 18 PTP
  Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02  EP 2 OUT
bmAttributes2
  Transfer TypeBulk
  Synch Type   None
  Usage Type   Data
wMaxPacketSize 0x0200  1x 512 bytes
bInterval   0
  Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81  EP 1 IN
bmAttributes2
  Transfer TypeBulk
  Synch Type   None
  Usage Type   Data
wMaxPacketSize 0x0200  1x 512 bytes
bInterval   0
  Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83  EP 3 IN
bmAttributes3
  Transfer TypeInterrupt
  Synch Type   None
  Usage Type   Data
wMaxPacketSize 0x0040  1x 64 bytes
bInterval  10
  Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength   0x0095
bNumInterfaces  3
bConfigurationValue 2
iConfiguration  6 iPod USB Interface
bmAttributes 0xc0
  Self Powered
MaxPower  500mA
Interface Descriptor:
  bLength 9
  bDescriptorType 4
  bInterfaceNumber0
  bAlternateSetting   0
  bNumEndpoints   0
  bInterfaceClass 1 Audio
  bInterfaceSubClass  1 Control Device
  bInterfaceProtocol  0 
  iInterface  0 
  AudioControl Interface Descriptor:
bLength 9
bDescriptorType36
bDescriptorSubtype  1 (HEADER)
bcdADC   1.00
wTotalLength   0x001e
bInCollection   1
baInterfaceNr(0)1
  AudioControl Interface Descriptor:
bLength12
bDescriptorType36
bDescriptorSubtype  2 (INPUT_TERMINAL)
bTerminalID 1
wTerminalType  0x0201 Microphone
bAssocTerminal  2
bNrChannels 2
wChannelConfig 0x0003
  Left Front (L)
  Right Front (R)
iChannelNames   0 
iTerminal   0 
  AudioControl Interface Descriptor:
bLength 9
bDescriptorType36
bDescriptorSubtype  3 (OUTPUT_TERMINAL)
bTerminalID 2
wTerminalType  0x0101 USB Streaming
bAssocTerminal  1
bSourceID   1
iTerminal   0 
Interface Descriptor:
  bLength 9
  bDescriptorType 4
 

Re: Driver for something that's neither a device nor an interface driver?

2019-09-27 Thread Bastien Nocera
On Fri, 2019-09-27 at 13:56 -0400, Alan Stern wrote:
> 

> Is there any reason this needs to be done in a kernel driver?

To offer a unified interface all the devices with similar needs.

>   Can it 
> be handled from userspace instead?

It could, at a great infrastructure cost, trying to get buy-in from
various distributions, at the very least.

> You said this was for a "power supply" class driver.  It's not clear 
> what that means -- the devices you want to communicate with are 
> iphones, ipads, etc., not power supplies.

There's tons of "device" scope "power_supply" devices in the kernel,
which don't power the Linux machine they're running on. Grep for
"POWER_SUPPLY_SCOPE_DEVICE" in the kernel, most wireless mice and
keyboards implement this already.

> Under what circumstances would these messages need to get sent?  

User-space would control it by changing the device's
POWER_SUPPLY_PROP_CHARGE_TYPE to "Fast", if available.

eg.
# echo "Fast" > /sys/devices/pci:00/:00:14.0/usb3/3-
1/power_supply/apple_mfi_fastcharge/charge_type

> What 
> piece of code is responsible for them?

In user-space? Hasn't been decided yet, but I can imagine a policy
daemon that cares about what devices charge from which other device,
and how fast. For example, a laptop in "low power mode" wouldn't want
to fast charge a phone, if the only reason the phone was plugged in was
to fetch some data off of it, for example.

> If necessary, you can modify the core/generic.c driver.  However
> that 
> might not be the right approach, considering that this is meant only 
> for devices manufactured by Apple.

It's also used by at least one Blackberry device, and I can imagine
other vendors having similar "APIs" to work-around USB 1.x charging
current limits.

I take it that by saying "modify core/generic.c" driver you mean that
it's not possible to inherit from it, right?



Re: Driver for something that's neither a device nor an interface driver?

2019-09-27 Thread Bastien Nocera
On Fri, 2019-09-27 at 20:57 +0200, Greg KH wrote:
> On Fri, Sep 27, 2019 at 07:44:08PM +0200, Bastien Nocera wrote:
> > On Fri, 2019-09-27 at 19:38 +0200, Greg KH wrote:
> > > What does the usb descriptors for the device look like?  Is it
> > > only
> > > the
> > > "default" control endpoint and no interfaces?  What does the
> > > output
> > > of
> > > 'usbdevices' show for the device?
> > 
> > The device in question can be an iPhone, an iPod Classic/Nano, or
> > an
> > iPad, amongst others, and they usually have useful interfaces, such
> > as
> > mass storage for the older ones, or ethernet, PTP, etc.
> 
> Ah.  Then why do you have to do this from a kernel driver?  Why can't
> you do this from userspace?

Because the kernel has a well-defined API for doing this sort of thing,
and I'd like device drivers to live in the kernel if they can live in
the kernel, making it easier to point at them when writing a policy
daemon, rather than getting told "I won't be using this daemon because
it uses the wrong language, or the wrong library".

I can imagine other implementation for other vendors once the ball
starts rolling.

> > > Normally you just bind to the "default" interface for the device,
> > > and
> > > all is good, there should be a few other drivers in the tree that
> > > do
> > > this, but I can't think of one off the top of my head at the
> > > moment.
> > 
> > All the interfaces (in the different configurations) are used for
> > something in the case of the iPhone 6S I'm trying to use.
> > 
> > I've attached the output of "lsusb -v" for the device below.
> 
> What about interface "9", the "Apple USB Multiplexor"?  What driver
> binds to that thing?  It's a vendor-specific protocol, so there
> shouldn't be any class driver assigned to it, unlike most of the
> other
> interfaces.

There's a user-space daemon called "usbmuxd" that will unbind it and
claim it. This daemon has the exact same API as this daemon under
macOS, and is a drop-in replacement too.

Finds the right configuration:
https://github.com/libimobiledevice/usbmuxd/blob/master/src/usb.h#L28
https://github.com/libimobiledevice/usbmuxd/blob/master/src/usb.c#L448
and claims it:
https://github.com/libimobiledevice/usbmuxd/blob/master/src/usb.c#L485



Re: Driver for something that's neither a device nor an interface driver?

2019-09-27 Thread Bastien Nocera
On Fri, 2019-09-27 at 21:25 +0200, Greg KH wrote:
> On Fri, Sep 27, 2019 at 08:49:12PM +0200, Bastien Nocera wrote:
> > On Fri, 2019-09-27 at 13:56 -0400, Alan Stern wrote:
> > 
> > > Is there any reason this needs to be done in a kernel driver?
> > 
> > To offer a unified interface all the devices with similar needs.
> 
> What "other devices with similar needs?"

I would expect Android phones to be able to offer up a different
charging method depending on policy, and wanting to be able to switch
charging methods.

> > >   Can it 
> > > be handled from userspace instead?
> > 
> > It could, at a great infrastructure cost, trying to get buy-in from
> > various distributions, at the very least.
> 
> For USB devices that _can_ be handled in userspace, we ask that they
> be
> done in userspace and not with a kernel driver.  Something that only
> does usb control messages with no other in-kernel api interfaces is
> ripe
> for a tiny userspace program using libusb.  Not for an in-kernel
> driver.

I don't quite understand why that would be when the kernel already
offers the API to be able to control it.

> > > You said this was for a "power supply" class driver.  It's not
> > > clear 
> > > what that means -- the devices you want to communicate with are 
> > > iphones, ipads, etc., not power supplies.
> > 
> > There's tons of "device" scope "power_supply" devices in the
> > kernel,
> > which don't power the Linux machine they're running on. Grep for
> > "POWER_SUPPLY_SCOPE_DEVICE" in the kernel, most wireless mice and
> > keyboards implement this already.
> 
> Yes, but those are real devices that the "Host" uses for power or
> something else.  wireless mice and keyboards already have kernel
> drivers
> so that's fine as well (but probably could be done from userspace
> too.)

It probably couldn't when the pipes to get key presses and the battery
info are the same.

> > > Under what circumstances would these messages need to get sent?  
> > 
> > User-space would control it by changing the device's
> > POWER_SUPPLY_PROP_CHARGE_TYPE to "Fast", if available.
> > 
> > eg.
> > # echo "Fast" > /sys/devices/pci:00/:00:14.0/usb3/3-
> > 1/power_supply/apple_mfi_fastcharge/charge_type
> 
> power_supply class is for the power supply that is charging the cpu
> you
> type that on.  Not for the cpu of an attached device, right?

Again, power_supply class has a scope attached to it, so having the
driver in the kernel would actually make it easier, with user-space not
having to care whether the device uses an "Apple" method or something
else.



Re: Driver for something that's neither a device nor an interface driver?

2019-09-28 Thread Bastien Nocera
On Sat, 2019-09-28 at 09:39 +0200, Greg KH wrote:
> On Fri, Sep 27, 2019 at 10:12:14PM +0200, Bastien Nocera wrote:
> > On Fri, 2019-09-27 at 21:25 +0200, Greg KH wrote:
> > > On Fri, Sep 27, 2019 at 08:49:12PM +0200, Bastien Nocera wrote:
> > > > On Fri, 2019-09-27 at 13:56 -0400, Alan Stern wrote:
> > > > 
> > > > > Is there any reason this needs to be done in a kernel driver?
> > > > 
> > > > To offer a unified interface all the devices with similar
> > > > needs.
> > > 
> > > What "other devices with similar needs?"
> > 
> > I would expect Android phones to be able to offer up a different
> > charging method depending on policy, and wanting to be able to
> > switch
> > charging methods.
> 
> I doubt it, it "should" be automatic based on the USB hardware
> configurations in the charger, not based on a random undocumented USB
> command sent from the host.  The USB spec describes how to do all of
> this properly without any commands at all, why not just rely on that?

That's not true, no. Until USB PD, there wasn't a way any ways for
devices to know that they could draw more current without either being
told so (as is done here), hardware modifications (with resistors being
wired to GND/VCC), or violating the USB spec.

In this case, Apple worked around the problem by having their OS,
running on their hardware, tell their peripherals to draw more power,
because the spec didn't allow this.

Those 2 articles should help understand the complexities of the
problem:
https://lwn.net/Articles/693027/
https://lwn.net/Articles/694062/

> Do you know of any Android device that requires a USB command like
> this?

Not that I could find, the Blackberry Q10 did though.

> > > > >   Can it 
> > > > > be handled from userspace instead?
> > > > 
> > > > It could, at a great infrastructure cost, trying to get buy-in
> > > > from
> > > > various distributions, at the very least.
> > > 
> > > For USB devices that _can_ be handled in userspace, we ask that
> > > they
> > > be
> > > done in userspace and not with a kernel driver.  Something that
> > > only
> > > does usb control messages with no other in-kernel api interfaces
> > > is
> > > ripe
> > > for a tiny userspace program using libusb.  Not for an in-kernel
> > > driver.
> > 
> > I don't quite understand why that would be when the kernel already
> > offers the API to be able to control it.
> 
> Again, if it _can_ be done in userspace, it _should_ be done in
> userspace when it comes to USB drivers/commands.

That's clear enough, although I still think it's wrong to try and move
to user-space things that have an existing clearly defined API in
kernel space. This would be akin to not allowing any new drivers for
webcams or USB sound cards because "they can be done in user-space".
Sure they can, but there's already an established API to handle them in
the kernel.

> > > > > You said this was for a "power supply" class driver.  It's
> > > > > not
> > > > > clear 
> > > > > what that means -- the devices you want to communicate with
> > > > > are 
> > > > > iphones, ipads, etc., not power supplies.
> > > > 
> > > > There's tons of "device" scope "power_supply" devices in the
> > > > kernel,
> > > > which don't power the Linux machine they're running on. Grep
> > > > for
> > > > "POWER_SUPPLY_SCOPE_DEVICE" in the kernel, most wireless mice
> > > > and
> > > > keyboards implement this already.
> > > 
> > > Yes, but those are real devices that the "Host" uses for power or
> > > something else.  wireless mice and keyboards already have kernel
> > > drivers
> > > so that's fine as well (but probably could be done from userspace
> > > too.)
> > 
> > It probably couldn't when the pipes to get key presses and the
> > battery
> > info are the same.
> 
> Are you sure?  They are really part of the USB HID spec?  Do you have
> pointers to that, for some reason I thought those were "out-of-band"
> vendor specific commands.

They're not part of the HID spec, but they don't have to be out-of-
band, or separate from the rest of the communication.

> > > > > Under what circumstances would these messages need to get
> > > > > sent?  
> > > > 
> > >

Re: Driver for something that's neither a device nor an interface driver?

2019-09-28 Thread Bastien Nocera
On Sat, 2019-09-28 at 14:18 +0200, Greg KH wrote:
> Again, the power_supply api is for power going the other way in the
> system.  That's not an "existing clearly defined API in kernel
> space".

No it isn't, not since 2011.

commit 25a0bc2dfc2ea732f40af2dae52426ead66ae76e
Author: Jeremy Fitzhardinge 
Date:   Wed Dec 7 11:24:20 2011 -0800

power_supply: add SCOPE attribute to power supplies

This adds a "scope" attribute to a power_supply, which indicates how
much of the system it powers.  It appears in sysfs as "scope" or in
the uevent file as POWER_SUPPLY_SCOPE=.  There are presently three
possible values:
Unknown - unknown power topology
System - the power supply powers the whole system
Device - it powers a specific device, or tree of devices

A power supply which doesn't have a "scope" attribute should be assumed to
have "System" scope.

In general, usermode should assume that loss of all System-scoped power
supplies will power off the whole system, but any single one is sufficient
to power the system.

Signed-off-by: Jeremy Fitzhardinge 
Cc: Richard Hughes 



Re: [PATCH] USB: rio500: Remove Rio 500 kernel driver

2019-10-03 Thread Bastien Nocera
On Mon, 2019-09-23 at 18:18 +0200, Bastien Nocera wrote:
> The Rio500 kernel driver has not been used by Rio500 owners since 2001
> not long after the rio500 project added support for a user-space USB stack
> through the very first versions of usbdevfs and then libusb.
> 
> Support for the kernel driver was removed from the upstream utilities
> in 2008:
> https://gitlab.freedesktop.org/hadess/rio500/commit/943f624ab721eb8281c287650fcc9e2026f6f5db
> 
> Cc: Cesar Miquel 
> Signed-off-by: Bastien Nocera 

Anything else I need to do to land this?

Cheers



Re: [PATCH] USB: rio500: Remove Rio 500 kernel driver

2019-10-03 Thread Bastien Nocera
On Thu, 2019-10-03 at 15:42 +0200, Greg Kroah-Hartman wrote:
> On Thu, Oct 03, 2019 at 03:18:16PM +0200, Bastien Nocera wrote:
> > On Mon, 2019-09-23 at 18:18 +0200, Bastien Nocera wrote:
> > > The Rio500 kernel driver has not been used by Rio500 owners since
> > > 2001
> > > not long after the rio500 project added support for a user-space
> > > USB stack
> > > through the very first versions of usbdevfs and then libusb.
> > > 
> > > Support for the kernel driver was removed from the upstream
> > > utilities
> > > in 2008:
> > > https://gitlab.freedesktop.org/hadess/rio500/commit/943f624ab721eb8281c287650fcc9e2026f6f5db
> > > 
> > > Cc: Cesar Miquel 
> > > Signed-off-by: Bastien Nocera 
> > 
> > Anything else I need to do to land this?
> 
> Patience, 5.4-rc1 just came out, my queue is 1500+ patches deep, I
> will
> dig through it in the next week...

No worries, was just expecting some/any feedback before long.



[PATCH 0/5] Add Apple MFi fastcharge USB device driver

2019-10-09 Thread Bastien Nocera
As discussed in the thread "Driver for something that's neither a
device nor an interface driver?", here's a patchset that makes it
possible for device drivers to extend the generic device driver.

An example usage is provided in the shape of a driver that allows
changing the charge type of an Apple MFi device to be fast.

Bastien Nocera (5):
  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: Add driver to control USB fast charge for iOS devices

 drivers/usb/core/driver.c   |  66 +++-
 drivers/usb/core/generic.c  |  49 ++-
 drivers/usb/core/usb.h  |   4 +
 drivers/usb/misc/Kconfig|  10 +
 drivers/usb/misc/Makefile   |   1 +
 drivers/usb/misc/apple-mfi-fastcharge.c | 500 
 include/linux/usb.h |   5 +
 7 files changed, 619 insertions(+), 16 deletions(-)
 create mode 100644 drivers/usb/misc/apple-mfi-fastcharge.c

-- 
2.21.0



[PATCH 2/5] USB: Make it possible to "subclass" usb_device_driver

2019-10-09 Thread Bastien Nocera
The 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.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c | 36 ++--
 include/linux/usb.h   |  1 +
 2 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 2b27d232d7a7..863e380a272b 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -261,10 +261,17 @@ 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);
-   return error;
+   if (udriver->generic_init)
+   error = usb_generic_driver_probe(udev);
+   if (error)
+   return error;
+
+   if (udriver->probe)
+   return udriver->probe(udev);
+   return 0;
 }
 
 /* called from driver core with dev locked */
@@ -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->generic_init)
+   usb_generic_driver_disconnect(udev);
+   if (udriver->disconnect)
+   udriver->disconnect(udev);
if (!udriver->supports_autosuspend)
usb_autosuspend_device(udev);
return 0;
@@ -886,6 +896,14 @@ int usb_register_device_driver(struct usb_device_driver 
*new_udriver,
if (usb_disabled())
return -ENODEV;
 
+   if (new_udriver->probe == NULL &&
+   !new_udriver->generic_init) {
+   printk(KERN_ERR "%s: error %d registering device "
+  "driver %s, no probe() function\n",
+  usbcore_name, retval, new_udriver->name);
+   return -EINVAL;
+   }
+
new_udriver->drvwrap.for_devices = 1;
new_udriver->drvwrap.driver.name = new_udriver->name;
new_udriver->drvwrap.driver.bus = &usb_bus_type;
@@ -1149,7 +1167,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->generic_init)
+   status = usb_generic_driver_suspend (udev, msg);
+   if (status == 0 && udriver->suspend)
+   status = udriver->suspend(udev, msg);
 
  done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
@@ -1181,7 +1202,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_init)
+   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);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index e656e7b4b1e4..fb9ad3511e55 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1242,6 +1242,7 @@ struct usb_device_driver {
const struct attribute_group **dev_groups;
struct usbdrv_wrap drvwrap;
unsigned int supports_autosuspend:1;
+   unsigned int generic_init:1;
 };
 #defineto_usb_device_driver(d) container_of(d, struct 
usb_device_driver, \
drvwrap.driver)
-- 
2.21.0



[PATCH 1/5] USB: Export generic USB device driver functions

2019-10-09 Thread Bastien Nocera
This will make it possible to implement device drivers which extend the
generic driver without needing to reimplement it.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/generic.c | 20 
 drivers/usb/core/usb.h |  4 
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 38f8b3e31762..7454c74d43ee 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -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;
 
@@ -221,8 +221,9 @@ static int generic_probe(struct usb_device *udev)
 
return 0;
 }
+EXPORT_SYMBOL_GPL(usb_generic_driver_probe);
 
-static void generic_disconnect(struct usb_device *udev)
+void usb_generic_driver_disconnect(struct usb_device *udev)
 {
usb_notify_remove_device(udev);
 
@@ -231,10 +232,11 @@ static void generic_disconnect(struct usb_device *udev)
if (udev->actconfig)
usb_set_configuration(udev, -1);
 }
+EXPORT_SYMBOL_GPL(usb_generic_driver_disconnect);
 
 #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;
 
@@ -261,8 +263,9 @@ static int generic_suspend(struct usb_device *udev, 
pm_message_t msg)
usbfs_notify_suspend(udev);
return rc;
 }
+EXPORT_SYMBOL_GPL(usb_generic_driver_suspend);
 
-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;
 
@@ -280,16 +283,17 @@ static int generic_resume(struct usb_device *udev, 
pm_message_t msg)
usbfs_notify_resume(udev);
return rc;
 }
+EXPORT_SYMBOL_GPL(usb_generic_driver_resume);
 
 #endif /* CONFIG_PM */
 
 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,
 };
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index cf4783cf661a..7423c4c5700f 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -47,6 +47,10 @@ 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)
-- 
2.21.0



[PATCH 4/5] USB: Select better matching USB drivers when available

2019-10-09 Thread Bastien Nocera
Now 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).

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c  | 15 +--
 drivers/usb/core/generic.c | 29 +
 include/linux/usb.h|  2 ++
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 50f92da8afcf..27ce63ed902d 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -819,13 +819,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;
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 7454c74d43ee..89f9c026a4d1 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -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;
@@ -289,6 +317,7 @@ EXPORT_SYMBOL_GPL(usb_generic_driver_resume);
 
 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
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 66bd4344e298..df5604f41118 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1236,6 +1236,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);
 
@@ -1243,6 +1244,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_init:1;
 };
-- 
2.21.0



[PATCH 3/5] USB: Implement usb_device_match_id()

2019-10-09 Thread Bastien Nocera
Match a usb_device with a table of IDs.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c | 15 +++
 include/linux/usb.h   |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 863e380a272b..50f92da8afcf 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -800,6 +800,21 @@ 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;
+}
+EXPORT_SYMBOL_GPL(usb_device_match_id);
+
 static int usb_device_match(struct device *dev, struct device_driver *drv)
 {
/* devices and interfaces are handled separately */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index fb9ad3511e55..66bd4344e298 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -864,6 +864,8 @@ const struct usb_device_id *usb_match_id(struct 
usb_interface *interface,
 const struct usb_device_id *id);
 extern int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id);
+const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
+   const struct usb_device_id *id);
 
 extern int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void 
*));
 extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
-- 
2.21.0



[PATCH 5/5] USB: Add driver to control USB fast charge for iOS devices

2019-10-09 Thread Bastien Nocera
iOS 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.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/misc/Kconfig|  10 +
 drivers/usb/misc/Makefile   |   1 +
 drivers/usb/misc/apple-mfi-fastcharge.c | 500 
 3 files changed, 511 insertions(+)
 create mode 100644 drivers/usb/misc/apple-mfi-fastcharge.c

diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index bdae62b2ffe0..f52a49478f1c 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -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
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 109f54f5b9aa..b75106cf3948 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -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
diff --git a/drivers/usb/misc/apple-mfi-fastcharge.c 
b/drivers/usb/misc/apple-mfi-fastcharge.c
new file mode 100644
index ..e28300018adc
--- /dev/null
+++ b/drivers/usb/misc/apple-mfi-fastcharge.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Fast-charge control for Apple "MFi" devices
+ *
+ * Copyright (C) 2019 Bastien Nocera 
+ */
+
+/* Standard include files */
+#include 
+#include 
+#include 
+#include 
+
+MODULE_AUTHOR("Bastien Nocera ");
+MODULE_DESCRIPTION("Fast-charge control for Apple \"MFi\" devices");
+MODULE_LICENSE("GPL");
+
+#define TRICKLE_CURRENT_MA 0
+#define FAST_CURRENT_MA2500
+
+#define APPLE_VENDOR_ID0x05ac  /* Apple */
+#define INTERFACE_NUMBER   0
+
+/* The product ID is defined as starting with 0x12nn, as per the
+ * "Choosing an Apple Device USB Configuration" section in
+ * release R9 (2012) of the "MFi Accessory Hardware Specification"
+ *
+ * To distinguish an Apple device, a USB host can check the device
+ * descriptor of attached USB devices for the following fields:
+ * ■ Vendor ID: 0x05AC
+ * ■ Product ID: 0x12nn
+ *
+ * The table is generated with the following lua program:
+ * i = 0x1200
+ * while i <= 0x12ff do
+ * print(string.format("\t{ USB_DEVICE(APPLE_VENDOR_ID, 0x%x) },", i))
+ * i = i + 1
+ * end
+ */
+
+static const struct usb_device_id id_table[] = {
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1200) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1201) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1202) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1203) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1204) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1205) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1206) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1207) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1208) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1209) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x120a) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x120b) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x120c) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x120d) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x120e) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x120f) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1210) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1211) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1212) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1213) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1214) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1215) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1216) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1217) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1218) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x1219) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x121a) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x121b) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x121c) },
+   { USB_DEVICE(APPLE_VENDOR_ID, 0x121d) },
+   { USB_DEVICE(APPLE_VENDOR_

Re: [PATCH 4/5] USB: Select better matching USB drivers when available

2019-10-09 Thread Bastien Nocera
On Wed, 2019-10-09 at 10:43 -0400, Alan Stern wrote:
> On Wed, 9 Oct 2019, Bastien Nocera wrote:
> 
> > Now 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).
> > 
> > Signed-off-by: Bastien Nocera 
> > ---
> >  drivers/usb/core/driver.c  | 15 +--
> >  drivers/usb/core/generic.c | 29 +
> >  include/linux/usb.h|  2 ++
> >  3 files changed, 44 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
> > index 50f92da8afcf..27ce63ed902d 100644
> > --- a/drivers/usb/core/driver.c
> > +++ b/drivers/usb/core/driver.c
> > @@ -819,13 +819,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;
> 
> What happens if the subclass driver's probe routine returns an
> error?  
> Don't you still want the device to be bound to the generic driver?

I don't know whether that's what you'd want to do. But if we did,
that'd only be for devices which have "generic_init" set.

We'd need to remember the result of the ->probe() call at the end of
usb_probe_device() (as modified in patch 2), and only call the generic
driver (not the specific device driver)'s functions in later usage.

Is that what you would expect?



Re: [PATCH 3/5] USB: Implement usb_device_match_id()

2019-10-09 Thread Bastien Nocera
On Wed, 2019-10-09 at 10:36 -0400, Alan Stern wrote:
> On Wed, 9 Oct 2019, Bastien Nocera wrote:
> 
> > Match a usb_device with a table of IDs.
> > 
> > Signed-off-by: Bastien Nocera 
> > ---
> >  drivers/usb/core/driver.c | 15 +++
> >  include/linux/usb.h   |  2 ++
> >  2 files changed, 17 insertions(+)
> > 
> > diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
> > index 863e380a272b..50f92da8afcf 100644
> > --- a/drivers/usb/core/driver.c
> > +++ b/drivers/usb/core/driver.c
> > @@ -800,6 +800,21 @@ 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;
> > + }
> 
> This would be better if you allowed matching against just the
> idVendor 
> field rather than matching against both.  That would make it a lot 
> simpler to match all Apple devices, for instance.

That should already be possible. The matching code is the same as for
the USB interface drivers.

Something like:
static const struct usb_device_id apple_match[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR,
  .idVendor = USB_VENDOR_APPLE
},
{}
}

And I couldn't use it in patch 5/5, as that's a range of product IDs,
not all of them (which would be quite a lot more).



Re: [PATCH 4/5] USB: Select better matching USB drivers when available

2019-10-09 Thread Bastien Nocera
On Wed, 2019-10-09 at 13:28 -0400, Alan Stern wrote:

> No, that's not quite it.
> 
> Here's what should happen when the subclass driver is being probed:
> First, call the generic_probe routine, and return immediately if that
> fails.  Then call the subclass driver's probe routine.  If that gets
> an
> error, fail the probe call but tell the device core that the device
> is
> now bound to the generic driver, not to the subclass driver.

So, something like that, on top of the existing patches? (I'm not sure
whether device_driver_attach is the correct call to use here).

-   if (udriver->probe)
-   return udriver->probe(udev);
-   return 0;
+   if (!udriver->probe)
+   return 0;
+   error = udriver->probe(udev);
+   if (error == -ENODEV &&
+   udrv != &usb_generic_driver)
+   return device_driver_attach(usb_generic_driver.drvwrap.driver, 
dev);
+   return error;

Anything else in this patch series? I was concerned about the naming
for "generic_init" in patch 2 ("subclass").

If there's nothing, I'll test and respin the patchset with the above
changes tomorrow.

Cheers



Re: [PATCH 2/5] USB: Make it possible to "subclass" usb_device_driver

2019-10-10 Thread Bastien Nocera
More replies inline (which I always miss)

On Wed, 2019-10-09 at 10:34 -0400, Alan Stern wrote:
> On Wed, 9 Oct 2019, Bastien Nocera wrote:
> 
> > The 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.
> 
> Presumably your first driver is in generic.c.  Where is the second
> one?
> 
> > 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.
> > 
> > Signed-off-by: Bastien Nocera 
> 
> This has a few problems.  The biggest one is that the device core
> does 
> not guarantee any order of driver probing.  If generic.c is probed 
> first, the subclass driver will never get probed -- which is a
> pretty 
> fatal flaw.
> 
> > ---
> >  drivers/usb/core/driver.c | 36 ++-
> -
> >  include/linux/usb.h   |  1 +
> >  2 files changed, 31 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
> > index 2b27d232d7a7..863e380a272b 100644
> > --- a/drivers/usb/core/driver.c
> > +++ b/drivers/usb/core/driver.c
> > @@ -261,10 +261,17 @@ 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);
> > - return error;
> > + if (udriver->generic_init)
> > + error = usb_generic_driver_probe(udev);
> > + if (error)
> > + return error;
> > +
> > + if (udriver->probe)
> > + return udriver->probe(udev);
> > + return 0;
> >  }
> >  
> >  /* called from driver core with dev locked */
> > @@ -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->generic_init)
> > + usb_generic_driver_disconnect(udev);
> > + if (udriver->disconnect)
> > + udriver->disconnect(udev);
> 
> The order is wrong.  The disconnects should always be done in
> reverse 
> order of probing.  This is true whenever you have a destructor for a 
> subclass; the subclasses destructor runs before the superclass's 
> destructor.

Fixed. Fixed in the suspend function as well.

> >   if (!udriver->supports_autosuspend)
> >   usb_autosuspend_device(udev);
> >   return 0;
> > @@ -886,6 +896,14 @@ int usb_register_device_driver(struct
> usb_device_driver *new_udriver,
> >   if (usb_disabled())
> >   return -ENODEV;
> >  
> > + if (new_udriver->probe == NULL &&
> > + !new_udriver->generic_init) {
> 
> There's no point adding this extra test.  Even subclass drivers
> should 
> have a probe function.

Removed.

> > + printk(KERN_ERR "%s: error %d registering device "
> > +"driver %s, no probe() function\n",
> 
> Don't split character strings.  They are an exception to the 80-
> column 
> limit.

I was using the error message just below in the function as an example.
A bad one apparently. This is gone in any case.

> > +usbcore_name, retval, new_udriver->name);
> > + return -EINVAL;
> > + }
> > +
> >   new_udriver->drvwrap.for_devices = 1;
> >   new_udriver->drvwrap.driver.name = new_udriver->name;
> >   new_udriver->drvwrap.driver.bus = &usb_bus_type;
> > @@ -1149,7 +1167,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->generic_init)
> > + status = usb_generic_driver_suspend (udev, msg);
> > + if (status == 0 && udriver->suspend)
> > + status = udriver->suspend(udev, msg);
> 
> Again, the order is wrong.  Suspend the subclass driver first.

Done, as mentioned ab

Re: [PATCH 4/5] USB: Select better matching USB drivers when available

2019-10-10 Thread Bastien Nocera
On Wed, 2019-10-09 at 14:45 -0400, Alan Stern wrote:
> 
On Wed, 9 Oct 2019, Bastien Nocera wrote:
> 
> 
> > +   return
> device_driver_attach(usb_generic_driver.drvwrap.driver, dev);
> > +   return error;
> 
> I think that's right.  A little testing wouldn't hurt.

device_driver_attach() isn't available to this part of the code.

I think the only way to do things here might be to set status bit for
the usb_device and launch device_reprobe(). The second time around, we
wouldn't match or probe the specific driver.



[PATCH v2 0/6] Add Apple MFi fastcharge USB device driver

2019-10-15 Thread Bastien Nocera
This is version 2 of the patch set.

- 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   |  59 +-
 drivers/usb/core/generic.c  |  48 -
 drivers/usb/core/usb.h  |   6 +
 drivers/usb/misc/Kconfig|  10 +
 drivers/usb/misc/Makefile   |   1 +
 drivers/usb/misc/apple-mfi-fastcharge.c | 237 
 include/linux/usb.h |   9 +
 8 files changed, 361 insertions(+), 15 deletions(-)
 create mode 100644 drivers/usb/misc/apple-mfi-fastcharge.c




[PATCH v2 5/6] USB: Fallback to generic driver when specific driver fails

2019-10-15 Thread Bastien Nocera
If ->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.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c  | 5 -
 drivers/usb/core/generic.c | 3 +++
 include/linux/usb.h| 1 +
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index e86065f3be7f..6190986c7d99 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -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;
 }
 
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 84da85c13825..4626227a6dd2 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -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.
diff --git a/include/linux/usb.h b/include/linux/usb.h
index a3f0142b816a..669579b37e54 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -708,6 +708,7 @@ struct usb_device {
unsigned lpm_disable_count;
 
u16 hub_delay;
+   unsigned use_generic_driver:1;
 };
 #defineto_usb_device(d) container_of(d, struct usb_device,
dev)
 



[PATCH v2 1/6] USB: Export generic USB device driver functions

2019-10-15 Thread Bastien Nocera
This will make it possible to implement device drivers which extend the
generic driver without needing to reimplement it.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/generic.c | 16 
 drivers/usb/core/usb.h |  6 ++
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 38f8b3e31762..28ece4d77749 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -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,
 };
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index cf4783cf661a..bbe24817315e 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -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)



[PATCH v2 4/6] USB: Select better matching USB drivers when available

2019-10-15 Thread Bastien Nocera
Now 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).

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c  | 15 +--
 drivers/usb/core/generic.c | 29 +
 include/linux/usb.h|  2 ++
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index cc3ca62111b4..e86065f3be7f 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -819,13 +819,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;
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 28ece4d77749..84da85c13825 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -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
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 7bf9b9b9e81b..a3f0142b816a 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1239,6 +1239,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);
 
@@ -1246,6 +1247,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;
 };



[PATCH v2 3/6] USB: Implement usb_device_match_id()

2019-10-15 Thread Bastien Nocera
Match a usb_device with a table of IDs.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c | 15 +++
 include/linux/usb.h   |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index d3787d084937..cc3ca62111b4 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -800,6 +800,21 @@ 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;
+}
+EXPORT_SYMBOL_GPL(usb_device_match_id);
+
 static int usb_device_match(struct device *dev, struct device_driver
*drv)
 {
/* devices and interfaces are handled separately */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 94bd3b48a485..7bf9b9b9e81b 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -864,6 +864,8 @@ const struct usb_device_id *usb_match_id(struct
usb_interface *interface,
 const struct usb_device_id
*id);
 extern int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id);
+const struct usb_device_id *usb_device_match_id(struct usb_device
*udev,
+   const struct usb_device_id *id);
 
 extern int usb_for_each_dev(void *data, int (*fn)(struct usb_device *,
void *));
 extern struct usb_interface *usb_find_interface(struct usb_driver
*drv,



[PATCH v2 2/6] USB: Make it possible to "subclass" usb_device_driver

2019-10-15 Thread Bastien Nocera
The 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.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c | 26 +-
 include/linux/usb.h   |  4 
 2 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 2b27d232d7a7..d3787d084937 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -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);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index e656e7b4b1e4..94bd3b48a485 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -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;
 };
 #defineto_usb_device_driver(d) container_of(d, struct
usb_device_driver, \
drvwrap.driver)



[PATCH v2 6/6] USB: Add driver to control USB fast charge for iOS devices

2019-10-15 Thread Bastien Nocera
iOS 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.

Signed-off-by: Bastien Nocera 
---
 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

diff --git a/MAINTAINERS b/MAINTAINERS
index 94ce075907a0..9e8f9fc972f5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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 
+L: linux-usb@vger.kernel.org
+S: Maintained
+F: drivers/usb/misc/apple-mfi-fastcharge.c
+
 USB AR5523 WIRELESS DRIVER
 M: Pontus Fuchs 
 L: linux-wirel...@vger.kernel.org
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index bdae62b2ffe0..f52a49478f1c 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -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
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 109f54f5b9aa..b75106cf3948 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -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
diff --git a/drivers/usb/misc/apple-mfi-fastcharge.c
b/drivers/usb/misc/apple-mfi-fastcharge.c
new file mode 100644
index ..f1c4461a9a3c
--- /dev/null
+++ b/drivers/usb/misc/apple-mfi-fastcharge.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Fast-charge control for Apple "MFi" devices
+ *
+ * Copyright (C) 2019 Bastien Nocera 
+ */
+
+/* Standard include files */
+#include 
+#include 
+#include 
+#include 
+
+MODULE_AUTHOR("Bastien Nocera ");
+MODULE_DESCRIPTION("Fast-charge control for Apple \"MFi\" devices");
+MODULE_LICENSE("GPL");
+
+#define TRICKLE_CURRENT_MA 0
+#define FAST_CURRENT_MA2500
+
+#define APPLE_VENDOR_ID0x05ac  /* Apple */
+
+/* The product ID is defined as starting with 0x12nn, as per the
+ * "Choosing an Apple Device USB Configuration" section in
+ * release R9 (2012) of the "MFi Accessory Hardware Specification"
+ *
+ * To distinguish an Apple device, a USB host can check the device
+ * descriptor of attached USB devices for the following fields:
+ * ■ Vendor ID: 0x05AC
+ * ■ Product ID: 0x12nn
+ *
+ * Those checks will be done in .match() and .probe().
+ */
+
+static const struct usb_device_id mfi_fc_id_table[] = {
+   { .idVendor = APPLE_VENDOR_ID,
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR },
+   {},
+};
+
+MODULE_DEVICE_TABLE(usb, mfi_fc_id_table);
+
+/* Driver-local specific stuff */
+struct mfi_device {
+   struct usb_device *udev;
+   struct power_supply *battery;
+   int charge_type;
+};
+
+static int apple_mfi_fc_set_charge_type(struct mfi_device *mfi,
+   const union
power_supply_propval *val)
+{
+   int current_ma;
+   int retval;
+   __u8 request_type;
+
+   if (mfi->charge_type == val->intval) {
+   dev_dbg(&mfi->udev->dev, "charge type %d already
set\n",
+   mfi->charge_type);
+   return 0;
+   }
+
+   switch (val->intval) {
+   case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
+   current_ma = TRICKLE_CURRENT_MA;
+   break;
+   case POWER_SUPPLY_CHARGE_TYPE_FAST:
+   current_ma = FAST_CURRENT_MA;
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   request_type = USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_D

Re: [PATCH v2 0/6] Add Apple MFi fastcharge USB device driver

2019-10-15 Thread Bastien Nocera
On Tue, 2019-10-15 at 16:27 +0200, Bastien Nocera wrote:
> This is version 2 of the patch set.
> 
> - checkpatch.pl is now quiet
> - fallback to the generic driver when driver ->probe() fails

And I'll send a v3 because all the patches got mangled by my mail
client.



[PATCH v2 0/6] Add Apple MFi fastcharge USB device driver

2019-10-15 Thread Bastien Nocera
This is version 2 of the patch set.

- 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   |  59 +-
 drivers/usb/core/generic.c  |  48 -
 drivers/usb/core/usb.h  |   6 +
 drivers/usb/misc/Kconfig|  10 +
 drivers/usb/misc/Makefile   |   1 +
 drivers/usb/misc/apple-mfi-fastcharge.c | 237 
 include/linux/usb.h |   9 +
 8 files changed, 361 insertions(+), 15 deletions(-)
 create mode 100644 drivers/usb/misc/apple-mfi-fastcharge.c

-- 
2.21.0



[PATCH v2 1/6] USB: Export generic USB device driver functions

2019-10-15 Thread Bastien Nocera
This will make it possible to implement device drivers which extend the
generic driver without needing to reimplement it.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/generic.c | 16 
 drivers/usb/core/usb.h |  6 ++
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 38f8b3e31762..28ece4d77749 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -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,
 };
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index cf4783cf661a..bbe24817315e 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -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)
-- 
2.21.0



[PATCH v2 2/6] USB: Make it possible to "subclass" usb_device_driver

2019-10-15 Thread Bastien Nocera
The 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.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c | 26 +-
 include/linux/usb.h   |  4 
 2 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 2b27d232d7a7..d3787d084937 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -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);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index e656e7b4b1e4..94bd3b48a485 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -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;
 };
 #defineto_usb_device_driver(d) container_of(d, struct 
usb_device_driver, \
drvwrap.driver)
-- 
2.21.0



[PATCH v2 4/6] USB: Select better matching USB drivers when available

2019-10-15 Thread Bastien Nocera
Now 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).

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c  | 15 +--
 drivers/usb/core/generic.c | 29 +
 include/linux/usb.h|  2 ++
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index cc3ca62111b4..e86065f3be7f 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -819,13 +819,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;
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 28ece4d77749..84da85c13825 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -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
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 7bf9b9b9e81b..a3f0142b816a 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1239,6 +1239,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);
 
@@ -1246,6 +1247,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;
 };
-- 
2.21.0



[PATCH v2 3/6] USB: Implement usb_device_match_id()

2019-10-15 Thread Bastien Nocera
Match a usb_device with a table of IDs.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c | 15 +++
 include/linux/usb.h   |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index d3787d084937..cc3ca62111b4 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -800,6 +800,21 @@ 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;
+}
+EXPORT_SYMBOL_GPL(usb_device_match_id);
+
 static int usb_device_match(struct device *dev, struct device_driver *drv)
 {
/* devices and interfaces are handled separately */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 94bd3b48a485..7bf9b9b9e81b 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -864,6 +864,8 @@ const struct usb_device_id *usb_match_id(struct 
usb_interface *interface,
 const struct usb_device_id *id);
 extern int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id);
+const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
+   const struct usb_device_id *id);
 
 extern int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void 
*));
 extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
-- 
2.21.0



[PATCH v2 5/6] USB: Fallback to generic driver when specific driver fails

2019-10-15 Thread Bastien Nocera
If ->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.

Signed-off-by: Bastien Nocera 
---
 drivers/usb/core/driver.c  | 5 -
 drivers/usb/core/generic.c | 3 +++
 include/linux/usb.h| 1 +
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index e86065f3be7f..6190986c7d99 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -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;
 }
 
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 84da85c13825..4626227a6dd2 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -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.
diff --git a/include/linux/usb.h b/include/linux/usb.h
index a3f0142b816a..669579b37e54 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -708,6 +708,7 @@ struct usb_device {
unsigned lpm_disable_count;
 
u16 hub_delay;
+   unsigned use_generic_driver:1;
 };
 #defineto_usb_device(d) container_of(d, struct usb_device, dev)
 
-- 
2.21.0



[PATCH v2 6/6] USB: Add driver to control USB fast charge for iOS devices

2019-10-15 Thread Bastien Nocera
iOS 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.

Signed-off-by: Bastien Nocera 
---
 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

diff --git a/MAINTAINERS b/MAINTAINERS
index 94ce075907a0..9e8f9fc972f5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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 
+L: linux-usb@vger.kernel.org
+S: Maintained
+F: drivers/usb/misc/apple-mfi-fastcharge.c
+
 USB AR5523 WIRELESS DRIVER
 M: Pontus Fuchs 
 L: linux-wirel...@vger.kernel.org
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index bdae62b2ffe0..f52a49478f1c 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -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
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 109f54f5b9aa..b75106cf3948 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -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
diff --git a/drivers/usb/misc/apple-mfi-fastcharge.c 
b/drivers/usb/misc/apple-mfi-fastcharge.c
new file mode 100644
index ..f1c4461a9a3c
--- /dev/null
+++ b/drivers/usb/misc/apple-mfi-fastcharge.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Fast-charge control for Apple "MFi" devices
+ *
+ * Copyright (C) 2019 Bastien Nocera 
+ */
+
+/* Standard include files */
+#include 
+#include 
+#include 
+#include 
+
+MODULE_AUTHOR("Bastien Nocera ");
+MODULE_DESCRIPTION("Fast-charge control for Apple \"MFi\" devices");
+MODULE_LICENSE("GPL");
+
+#define TRICKLE_CURRENT_MA 0
+#define FAST_CURRENT_MA2500
+
+#define APPLE_VENDOR_ID0x05ac  /* Apple */
+
+/* The product ID is defined as starting with 0x12nn, as per the
+ * "Choosing an Apple Device USB Configuration" section in
+ * release R9 (2012) of the "MFi Accessory Hardware Specification"
+ *
+ * To distinguish an Apple device, a USB host can check the device
+ * descriptor of attached USB devices for the following fields:
+ * ■ Vendor ID: 0x05AC
+ * ■ Product ID: 0x12nn
+ *
+ * Those checks will be done in .match() and .probe().
+ */
+
+static const struct usb_device_id mfi_fc_id_table[] = {
+   { .idVendor = APPLE_VENDOR_ID,
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR },
+   {},
+};
+
+MODULE_DEVICE_TABLE(usb, mfi_fc_id_table);
+
+/* Driver-local specific stuff */
+struct mfi_device {
+   struct usb_device *udev;
+   struct power_supply *battery;
+   int charge_type;
+};
+
+static int apple_mfi_fc_set_charge_type(struct mfi_device *mfi,
+   const union power_supply_propval *val)
+{
+   int current_ma;
+   int retval;
+   __u8 request_type;
+
+   if (mfi->charge_type == val->intval) {
+   dev_dbg(&mfi->udev->dev, "charge type %d already set\n",
+   mfi->charge_type);
+   return 0;
+   }
+
+   switch (val->intval) {
+   case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
+   current_ma = TRICKLE_CURRENT_MA;
+   break;
+   case POWER_SUPPLY_CHARGE_TYPE_FAST:
+   current_ma = FAST_CURRENT_MA;
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   request_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_D

[PATCH v3 1/6] USB: Export generic USB device driver functions

2019-10-16 Thread Bastien Nocera
This will make it possible to implement device drivers which extend the
generic driver without needing to reimplement it.

Signed-off-by: Bastien Nocera 
Acked-by: Alan Stern 
---
 drivers/usb/core/generic.c | 16 
 drivers/usb/core/usb.h |  6 ++
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git drivers/usb/core/generic.c drivers/usb/core/generic.c
index 38f8b3e31762..28ece4d77749 100644
--- drivers/usb/core/generic.c
+++ drivers/usb/core/generic.c
@@ -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,
 };
diff --git drivers/usb/core/usb.h drivers/usb/core/usb.h
index cf4783cf661a..bbe24817315e 100644
--- drivers/usb/core/usb.h
+++ drivers/usb/core/usb.h
@@ -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)
-- 
2.21.0



[PATCH v3 2/6] USB: Make it possible to "subclass" usb_device_driver

2019-10-16 Thread Bastien Nocera
The 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.

Signed-off-by: Bastien Nocera 
Acked-by: Alan Stern 
---
 drivers/usb/core/driver.c | 26 +-
 include/linux/usb.h   |  4 
 2 files changed, 25 insertions(+), 5 deletions(-)

diff --git drivers/usb/core/driver.c drivers/usb/core/driver.c
index 2b27d232d7a7..d3787d084937 100644
--- drivers/usb/core/driver.c
+++ drivers/usb/core/driver.c
@@ -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);
diff --git include/linux/usb.h include/linux/usb.h
index e656e7b4b1e4..94bd3b48a485 100644
--- include/linux/usb.h
+++ include/linux/usb.h
@@ -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;
 };
 #defineto_usb_device_driver(d) container_of(d, struct 
usb_device_driver, \
drvwrap.driver)
-- 
2.21.0



[PATCH v3 3/6] USB: Implement usb_device_match_id()

2019-10-16 Thread Bastien Nocera
Match a usb_device with a table of IDs.

Signed-off-by: Bastien Nocera 
Acked-by: Alan Stern 
---
 drivers/usb/core/driver.c | 14 ++
 drivers/usb/core/usb.h|  2 ++
 2 files changed, 16 insertions(+)

diff --git drivers/usb/core/driver.c drivers/usb/core/driver.c
index d3787d084937..697898327b44 100644
--- drivers/usb/core/driver.c
+++ drivers/usb/core/driver.c
@@ -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 */
diff --git drivers/usb/core/usb.h drivers/usb/core/usb.h
index bbe24817315e..f1dc63848219 100644
--- drivers/usb/core/usb.h
+++ drivers/usb/core/usb.h
@@ -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);
 
-- 
2.21.0



[PATCH v3 5/6] USB: Fallback to generic driver when specific driver fails

2019-10-16 Thread Bastien Nocera
If ->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.

Signed-off-by: Bastien Nocera 
Acked-by: Alan Stern 
---
 drivers/usb/core/driver.c  | 5 -
 drivers/usb/core/generic.c | 3 +++
 include/linux/usb.h| 1 +
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git drivers/usb/core/driver.c drivers/usb/core/driver.c
index 9d1502a9571d..f81606c6a35b 100644
--- drivers/usb/core/driver.c
+++ drivers/usb/core/driver.c
@@ -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;
 }
 
diff --git drivers/usb/core/generic.c drivers/usb/core/generic.c
index 84da85c13825..4626227a6dd2 100644
--- drivers/usb/core/generic.c
+++ drivers/usb/core/generic.c
@@ -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.
diff --git include/linux/usb.h include/linux/usb.h
index 3663bd7b1fa4..ca1a5f1e1c5e 100644
--- include/linux/usb.h
+++ include/linux/usb.h
@@ -708,6 +708,7 @@ struct usb_device {
unsigned lpm_disable_count;
 
u16 hub_delay;
+   unsigned use_generic_driver:1;
 };
 #defineto_usb_device(d) container_of(d, struct usb_device, dev)
 
-- 
2.21.0



[PATCH v3 4/6] USB: Select better matching USB drivers when available

2019-10-16 Thread Bastien Nocera
Now 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).

Signed-off-by: Bastien Nocera 
Acked-by: Alan Stern 
---
 drivers/usb/core/driver.c  | 15 +--
 drivers/usb/core/generic.c | 29 +
 include/linux/usb.h|  2 ++
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git drivers/usb/core/driver.c drivers/usb/core/driver.c
index 697898327b44..9d1502a9571d 100644
--- drivers/usb/core/driver.c
+++ drivers/usb/core/driver.c
@@ -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;
diff --git drivers/usb/core/generic.c drivers/usb/core/generic.c
index 28ece4d77749..84da85c13825 100644
--- drivers/usb/core/generic.c
+++ drivers/usb/core/generic.c
@@ -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
diff --git include/linux/usb.h include/linux/usb.h
index 94bd3b48a485..3663bd7b1fa4 100644
--- include/linux/usb.h
+++ include/linux/usb.h
@@ -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;
 };
-- 
2.21.0



[PATCH v3 6/6] USB: Add driver to control USB fast charge for iOS devices

2019-10-16 Thread Bastien Nocera
iOS 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.

Signed-off-by: Bastien Nocera 
Acked-by: Alan Stern 
---
 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

diff --git MAINTAINERS MAINTAINERS
index 94ce075907a0..9e8f9fc972f5 100644
--- MAINTAINERS
+++ MAINTAINERS
@@ -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 
+L: linux-usb@vger.kernel.org
+S: Maintained
+F: drivers/usb/misc/apple-mfi-fastcharge.c
+
 USB AR5523 WIRELESS DRIVER
 M: Pontus Fuchs 
 L: linux-wirel...@vger.kernel.org
diff --git drivers/usb/misc/Kconfig drivers/usb/misc/Kconfig
index bdae62b2ffe0..f52a49478f1c 100644
--- drivers/usb/misc/Kconfig
+++ drivers/usb/misc/Kconfig
@@ -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
diff --git drivers/usb/misc/Makefile drivers/usb/misc/Makefile
index 109f54f5b9aa..b75106cf3948 100644
--- drivers/usb/misc/Makefile
+++ drivers/usb/misc/Makefile
@@ -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
diff --git drivers/usb/misc/apple-mfi-fastcharge.c 
drivers/usb/misc/apple-mfi-fastcharge.c
new file mode 100644
index ..f1c4461a9a3c
--- /dev/null
+++ drivers/usb/misc/apple-mfi-fastcharge.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Fast-charge control for Apple "MFi" devices
+ *
+ * Copyright (C) 2019 Bastien Nocera 
+ */
+
+/* Standard include files */
+#include 
+#include 
+#include 
+#include 
+
+MODULE_AUTHOR("Bastien Nocera ");
+MODULE_DESCRIPTION("Fast-charge control for Apple \"MFi\" devices");
+MODULE_LICENSE("GPL");
+
+#define TRICKLE_CURRENT_MA 0
+#define FAST_CURRENT_MA2500
+
+#define APPLE_VENDOR_ID0x05ac  /* Apple */
+
+/* The product ID is defined as starting with 0x12nn, as per the
+ * "Choosing an Apple Device USB Configuration" section in
+ * release R9 (2012) of the "MFi Accessory Hardware Specification"
+ *
+ * To distinguish an Apple device, a USB host can check the device
+ * descriptor of attached USB devices for the following fields:
+ * ■ Vendor ID: 0x05AC
+ * ■ Product ID: 0x12nn
+ *
+ * Those checks will be done in .match() and .probe().
+ */
+
+static const struct usb_device_id mfi_fc_id_table[] = {
+   { .idVendor = APPLE_VENDOR_ID,
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR },
+   {},
+};
+
+MODULE_DEVICE_TABLE(usb, mfi_fc_id_table);
+
+/* Driver-local specific stuff */
+struct mfi_device {
+   struct usb_device *udev;
+   struct power_supply *battery;
+   int charge_type;
+};
+
+static int apple_mfi_fc_set_charge_type(struct mfi_device *mfi,
+   const union power_supply_propval *val)
+{
+   int current_ma;
+   int retval;
+   __u8 request_type;
+
+   if (mfi->charge_type == val->intval) {
+   dev_dbg(&mfi->udev->dev, "charge type %d already set\n",
+   mfi->charge_type);
+   return 0;
+   }
+
+   switch (val->intval) {
+   case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
+   current_ma = TRICKLE_CURRENT_MA;
+   break;
+   case POWER_SUPPLY_CHARGE_TYPE_FAST:
+   current_ma = FAST_CURRENT_MA;
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   request_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_D

[PATCH v3 0/6] Add Apple MFi fastcharge USB device driver

2019-10-16 Thread Bastien Nocera
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

-- 
2.21.0