Message ID | 20220726005824.2817646-2-vi@endrift.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [1/2] USB: gadget: f_hid: Add Get-Feature report | expand |
В Mon, 25 Jul 2022 17:58:26 -0700 Vicki Pfau <vi@endrift.com> пишет: > While the HID gadget implementation has been sufficient for devices that only > use INTERRUPT transfers, the USB HID standard includes provisions for Set- and > Get-Feature report CONTROL transfers that go over endpoint 0. These were > previously impossible with the existing implementation, and would either send > an empty reply, or stall out. > > As the feature is a standard part of USB HID, it stands to reason that devices > would use it, and that the HID gadget should support it. This patch adds > support for host-to-device Set-Feature reports through a new ioctl > interface to the hidg class dev nodes. > > Signed-off-by: Vicki Pfau <vi@endrift.com> Won't it break the logic of the existing software that works with /dev/hidgX? Will it work if I want my gadget to work the old way? It is important that the old behavior is the default without having to use the new ioctls. As for these ioctls, since this is an addition to the new API, they should be documented. I think it's also worth adding these ioctls to the userspace example: - Documentation/usb/gadget_hid.rst - Documentation/usb/gadget-testing.rst But it seems to me that extending the HID functionality to meet the specifications is definitely a good idea :)
On 7/26/22 02:51, Maxim Devaev wrote: > В Mon, 25 Jul 2022 17:58:26 -0700 > Vicki Pfau <vi@endrift.com> пишет: > >> While the HID gadget implementation has been sufficient for devices that only >> use INTERRUPT transfers, the USB HID standard includes provisions for Set- and >> Get-Feature report CONTROL transfers that go over endpoint 0. These were >> previously impossible with the existing implementation, and would either send >> an empty reply, or stall out. >> >> As the feature is a standard part of USB HID, it stands to reason that devices >> would use it, and that the HID gadget should support it. This patch adds >> support for host-to-device Set-Feature reports through a new ioctl >> interface to the hidg class dev nodes. >> >> Signed-off-by: Vicki Pfau <vi@endrift.com> > > Won't it break the logic of the existing software that works with /dev/hidgX? > Will it work if I want my gadget to work the old way? For existing software to use SET_FEATURE at all it has to use an alternative mode, which seems to have only been added somewhat recently. That mode also appears to preclude use of INTERRUPT transfers at all, unless there's some way to set up two hidg nodes that map to the same interface, with one for INTERRUPT and one for SET_FEATURE. If this breaks that, I suppose that's a regression, but this is meant to augment the original, long-standing mode so you can mix INTERRUPT and SET/GET_FEATURE transfers, as there is no way to do that yet. Honestly, the alternate mode seems more like a workaround, as far as I can tell, and not an ideal implementation. I'm not sure when it was added, but as I was originally authoring this against 5.13 and didn't see it until I went to rebase onto master, it can't have been that long ago. So if it breaks any software (which I don't believe it does), it would only affect very new software. As I alluded to, I'd thought about perhaps adding a second node per interface so one would act as INTERRUPT transfers and the other as SET/GET_FEATURE transfers, but I already had this code half written and wanted to get feedback first, especially since what I have now works (although it's not well-tested after rebasing). > It is important that the old behavior is the default without having to use > the new ioctls. As for these ioctls, since this is an addition to the new API, > they should be documented. I think it's also worth adding these ioctls > to the userspace example: > - Documentation/usb/gadget_hid.rst > - Documentation/usb/gadget-testing.rst Yup, I should probably do that. Forgot about that before sending the patch, though I'm hoping to be told if my approach was even worthwhile before I write that, but I can work on that soon either way. > > But it seems to me that extending the HID functionality to meet > the specifications is definitely a good idea :)
В Tue, 26 Jul 2022 21:26:05 -0700 Vicki Pfau <vi@endrift.com> пишет: > On 7/26/22 02:51, Maxim Devaev wrote: > > В Mon, 25 Jul 2022 17:58:26 -0700 > > Vicki Pfau <vi@endrift.com> пишет: > > > >> While the HID gadget implementation has been sufficient for devices that only > >> use INTERRUPT transfers, the USB HID standard includes provisions for Set- and > >> Get-Feature report CONTROL transfers that go over endpoint 0. These were > >> previously impossible with the existing implementation, and would either send > >> an empty reply, or stall out. > >> > >> As the feature is a standard part of USB HID, it stands to reason that devices > >> would use it, and that the HID gadget should support it. This patch adds > >> support for host-to-device Set-Feature reports through a new ioctl > >> interface to the hidg class dev nodes. > >> > >> Signed-off-by: Vicki Pfau <vi@endrift.com> > > > > Won't it break the logic of the existing software that works with /dev/hidgX? > > Will it work if I want my gadget to work the old way? > > For existing software to use SET_FEATURE at all it has to use an alternative mode, which seems to have only been added somewhat recently. That mode also appears to preclude use of INTERRUPT transfers at all, unless there's some way to set up two hidg nodes that map to the same interface, with one for INTERRUPT and one for SET_FEATURE. If this breaks that, I suppose that's a regression, but this is meant to augment the original, long-standing mode so you can mix INTERRUPT and SET/GET_FEATURE transfers, as there is no way to do that yet. Honestly, the alternate mode seems more like a workaround, as far as I can tell, and not an ideal implementation. I'm not sure when it was added, but as I was originally authoring this against 5.13 and didn't see it until I went to rebase onto master, it can't have been that long ago. So if it breaks any software (which I don't believe it does), it would only affect very new software. > > As I alluded to, I'd thought about perhaps adding a second node per interface so one would act as INTERRUPT transfers and the other as SET/GET_FEATURE transfers, but I already had this code half written and wanted to get feedback first, especially since what I have now works (although it's not well-tested after rebasing). I'm a little confused here about what you call an alternative mode. Are we talking about use_out_ep=1 (default behavior with INTERRUPT) or use_out_ep=0 (SETUP/SET_REPORT)? The last mode was added by me to ensure strict compatibility with Apple UEFI and strange BIOS, and this mode is actually actively used. It is important to me that it is not broken, but unfortunately I cannot test your patch on my kernel, as I temporarily do not have access to testing equipment.
On 7/28/22 01:59, Maxim Devaev wrote: > В Tue, 26 Jul 2022 21:26:05 -0700 > Vicki Pfau <vi@endrift.com> пишет: > >> On 7/26/22 02:51, Maxim Devaev wrote: >>> В Mon, 25 Jul 2022 17:58:26 -0700 >>> Vicki Pfau <vi@endrift.com> пишет: >>> >>>> While the HID gadget implementation has been sufficient for devices that only >>>> use INTERRUPT transfers, the USB HID standard includes provisions for Set- and >>>> Get-Feature report CONTROL transfers that go over endpoint 0. These were >>>> previously impossible with the existing implementation, and would either send >>>> an empty reply, or stall out. >>>> >>>> As the feature is a standard part of USB HID, it stands to reason that devices >>>> would use it, and that the HID gadget should support it. This patch adds >>>> support for host-to-device Set-Feature reports through a new ioctl >>>> interface to the hidg class dev nodes. >>>> >>>> Signed-off-by: Vicki Pfau <vi@endrift.com> >>> >>> Won't it break the logic of the existing software that works with /dev/hidgX? >>> Will it work if I want my gadget to work the old way? >> >> For existing software to use SET_FEATURE at all it has to use an alternative mode, which seems to have only been added somewhat recently. That mode also appears to preclude use of INTERRUPT transfers at all, unless there's some way to set up two hidg nodes that map to the same interface, with one for INTERRUPT and one for SET_FEATURE. If this breaks that, I suppose that's a regression, but this is meant to augment the original, long-standing mode so you can mix INTERRUPT and SET/GET_FEATURE transfers, as there is no way to do that yet. Honestly, the alternate mode seems more like a workaround, as far as I can tell, and not an ideal implementation. I'm not sure when it was added, but as I was originally authoring this against 5.13 and didn't see it until I went to rebase onto master, it can't have been that long ago. So if it breaks any software (which I don't believe it does), it would only affect very new software. >> >> As I alluded to, I'd thought about perhaps adding a second node per interface so one would act as INTERRUPT transfers and the other as SET/GET_FEATURE transfers, but I already had this code half written and wanted to get feedback first, especially since what I have now works (although it's not well-tested after rebasing). > > I'm a little confused here about what you call an alternative mode. > Are we talking about use_out_ep=1 (default behavior with INTERRUPT) > or use_out_ep=0 (SETUP/SET_REPORT)? The last mode was added by me > to ensure strict compatibility with Apple UEFI and strange BIOS, > and this mode is actually actively used. It is important to me > that it is not broken, but unfortunately I cannot test your patch > on my kernel, as I temporarily do not have access to testing equipment. use_out_ep=0 is the alternate mode I was talking about. It didn't exist in 5.13, so as I said I wasn't aware of it until I rebased. As the device I'm using is still stuck on that old kernel (for now) and I don't know if I have any USB gadget capable devices on new kernels, I was unable to test it, and would very much like to make sure it doesn't regress before a patch is merged. I wasn't intending to break it, but I figured I'd get feedback I'd need to change before this was merged so if you could test it to ensure it doesn't regress any behavior that would be much appreciated and help me out. I will probably wait until then before submitting a v2.
В Thu, 28 Jul 2022 11:11:31 -0700 Vicki Pfau <vi@endrift.com> пишет: > On 7/28/22 01:59, Maxim Devaev wrote: > > В Tue, 26 Jul 2022 21:26:05 -0700 > > Vicki Pfau <vi@endrift.com> пишет: > > > >> On 7/26/22 02:51, Maxim Devaev wrote: > >>> В Mon, 25 Jul 2022 17:58:26 -0700 > >>> Vicki Pfau <vi@endrift.com> пишет: > >>> > >>>> While the HID gadget implementation has been sufficient for devices that only > >>>> use INTERRUPT transfers, the USB HID standard includes provisions for Set- and > >>>> Get-Feature report CONTROL transfers that go over endpoint 0. These were > >>>> previously impossible with the existing implementation, and would either send > >>>> an empty reply, or stall out. > >>>> > >>>> As the feature is a standard part of USB HID, it stands to reason that devices > >>>> would use it, and that the HID gadget should support it. This patch adds > >>>> support for host-to-device Set-Feature reports through a new ioctl > >>>> interface to the hidg class dev nodes. > >>>> > >>>> Signed-off-by: Vicki Pfau <vi@endrift.com> > >>> > >>> Won't it break the logic of the existing software that works with /dev/hidgX? > >>> Will it work if I want my gadget to work the old way? > >> > >> For existing software to use SET_FEATURE at all it has to use an alternative mode, which seems to have only been added somewhat recently. That mode also appears to preclude use of INTERRUPT transfers at all, unless there's some way to set up two hidg nodes that map to the same interface, with one for INTERRUPT and one for SET_FEATURE. If this breaks that, I suppose that's a regression, but this is meant to augment the original, long-standing mode so you can mix INTERRUPT and SET/GET_FEATURE transfers, as there is no way to do that yet. Honestly, the alternate mode seems more like a workaround, as far as I can tell, and not an ideal implementation. I'm not sure when it was added, but as I was originally authoring this against 5.13 and didn't see it until I went to rebase onto master, it can't have been that long ago. So if it breaks any software (which I don't believe it does), it would only affect very new software. > >> > >> As I alluded to, I'd thought about perhaps adding a second node per interface so one would act as INTERRUPT transfers and the other as SET/GET_FEATURE transfers, but I already had this code half written and wanted to get feedback first, especially since what I have now works (although it's not well-tested after rebasing). > > > > I'm a little confused here about what you call an alternative mode. > > Are we talking about use_out_ep=1 (default behavior with INTERRUPT) > > or use_out_ep=0 (SETUP/SET_REPORT)? The last mode was added by me > > to ensure strict compatibility with Apple UEFI and strange BIOS, > > and this mode is actually actively used. It is important to me > > that it is not broken, but unfortunately I cannot test your patch > > on my kernel, as I temporarily do not have access to testing equipment. > > use_out_ep=0 is the alternate mode I was talking about. It didn't exist in 5.13, so as I said I wasn't aware of it until I rebased. As the device I'm using is still stuck on that old kernel (for now) and I don't know if I have any USB gadget capable devices on new kernels, I was unable to test it, and would very much like to make sure it doesn't regress before a patch is merged. I wasn't intending to break it, but I figured I'd get feedback I'd need to change before this was merged so if you could test it to ensure it doesn't regress any behavior that would be much appreciated and help me out. I will probably wait until then before submitting a v2. I will get access to the USB analyzer and test environment in about a month, if that suits you. You can write directly to my email after a month, I will help you with testing.
On 7/31/22 01:14, Maxim Devaev wrote: > В Thu, 28 Jul 2022 11:11:31 -0700 > Vicki Pfau <vi@endrift.com> пишет: > >> On 7/28/22 01:59, Maxim Devaev wrote: >>> В Tue, 26 Jul 2022 21:26:05 -0700 >>> Vicki Pfau <vi@endrift.com> пишет: >>> >>>> On 7/26/22 02:51, Maxim Devaev wrote: >>>>> В Mon, 25 Jul 2022 17:58:26 -0700 >>>>> Vicki Pfau <vi@endrift.com> пишет: >>>>> >>>>>> While the HID gadget implementation has been sufficient for devices that only >>>>>> use INTERRUPT transfers, the USB HID standard includes provisions for Set- and >>>>>> Get-Feature report CONTROL transfers that go over endpoint 0. These were >>>>>> previously impossible with the existing implementation, and would either send >>>>>> an empty reply, or stall out. >>>>>> >>>>>> As the feature is a standard part of USB HID, it stands to reason that devices >>>>>> would use it, and that the HID gadget should support it. This patch adds >>>>>> support for host-to-device Set-Feature reports through a new ioctl >>>>>> interface to the hidg class dev nodes. >>>>>> >>>>>> Signed-off-by: Vicki Pfau <vi@endrift.com> >>>>> >>>>> Won't it break the logic of the existing software that works with /dev/hidgX? >>>>> Will it work if I want my gadget to work the old way? >>>> >>>> For existing software to use SET_FEATURE at all it has to use an alternative mode, which seems to have only been added somewhat recently. That mode also appears to preclude use of INTERRUPT transfers at all, unless there's some way to set up two hidg nodes that map to the same interface, with one for INTERRUPT and one for SET_FEATURE. If this breaks that, I suppose that's a regression, but this is meant to augment the original, long-standing mode so you can mix INTERRUPT and SET/GET_FEATURE transfers, as there is no way to do that yet. Honestly, the alternate mode seems more like a workaround, as far as I can tell, and not an ideal implementation. I'm not sure when it was added, but as I was originally authoring this against 5.13 and didn't see it until I went to rebase onto master, it can't have been that long ago. So if it breaks any software (which I don't believe it does), it would only affect very new software. >>>> >>>> As I alluded to, I'd thought about perhaps adding a second node per interface so one would act as INTERRUPT transfers and the other as SET/GET_FEATURE transfers, but I already had this code half written and wanted to get feedback first, especially since what I have now works (although it's not well-tested after rebasing). >>> >>> I'm a little confused here about what you call an alternative mode. >>> Are we talking about use_out_ep=1 (default behavior with INTERRUPT) >>> or use_out_ep=0 (SETUP/SET_REPORT)? The last mode was added by me >>> to ensure strict compatibility with Apple UEFI and strange BIOS, >>> and this mode is actually actively used. It is important to me >>> that it is not broken, but unfortunately I cannot test your patch >>> on my kernel, as I temporarily do not have access to testing equipment. >> >> use_out_ep=0 is the alternate mode I was talking about. It didn't exist in 5.13, so as I said I wasn't aware of it until I rebased. As the device I'm using is still stuck on that old kernel (for now) and I don't know if I have any USB gadget capable devices on new kernels, I was unable to test it, and would very much like to make sure it doesn't regress before a patch is merged. I wasn't intending to break it, but I figured I'd get feedback I'd need to change before this was merged so if you could test it to ensure it doesn't regress any behavior that would be much appreciated and help me out. I will probably wait until then before submitting a v2. > > I will get access to the USB analyzer and test environment in about a month, > if that suits you. You can write directly to my email after a month, > I will help you with testing. I'm not in a huge rush, though I might try to find some hardware I can test a modern kernel on to help test. What are you running the kernel on?
В Wed, 3 Aug 2022 16:32:21 -0700 Vicki Pfau <vi@endrift.com> пишет: > On 7/31/22 01:14, Maxim Devaev wrote: > > В Thu, 28 Jul 2022 11:11:31 -0700 > > Vicki Pfau <vi@endrift.com> пишет: > > > >> On 7/28/22 01:59, Maxim Devaev wrote: > >>> В Tue, 26 Jul 2022 21:26:05 -0700 > >>> Vicki Pfau <vi@endrift.com> пишет: > >>> > >>>> On 7/26/22 02:51, Maxim Devaev wrote: > >>>>> В Mon, 25 Jul 2022 17:58:26 -0700 > >>>>> Vicki Pfau <vi@endrift.com> пишет: > >>>>> > >>>>>> While the HID gadget implementation has been sufficient for devices that only > >>>>>> use INTERRUPT transfers, the USB HID standard includes provisions for Set- and > >>>>>> Get-Feature report CONTROL transfers that go over endpoint 0. These were > >>>>>> previously impossible with the existing implementation, and would either send > >>>>>> an empty reply, or stall out. > >>>>>> > >>>>>> As the feature is a standard part of USB HID, it stands to reason that devices > >>>>>> would use it, and that the HID gadget should support it. This patch adds > >>>>>> support for host-to-device Set-Feature reports through a new ioctl > >>>>>> interface to the hidg class dev nodes. > >>>>>> > >>>>>> Signed-off-by: Vicki Pfau <vi@endrift.com> > >>>>> > >>>>> Won't it break the logic of the existing software that works with /dev/hidgX? > >>>>> Will it work if I want my gadget to work the old way? > >>>> > >>>> For existing software to use SET_FEATURE at all it has to use an alternative mode, which seems to have only been added somewhat recently. That mode also appears to preclude use of INTERRUPT transfers at all, unless there's some way to set up two hidg nodes that map to the same interface, with one for INTERRUPT and one for SET_FEATURE. If this breaks that, I suppose that's a regression, but this is meant to augment the original, long-standing mode so you can mix INTERRUPT and SET/GET_FEATURE transfers, as there is no way to do that yet. Honestly, the alternate mode seems more like a workaround, as far as I can tell, and not an ideal implementation. I'm not sure when it was added, but as I was originally authoring this against 5.13 and didn't see it until I went to rebase onto master, it can't have been that long ago. So if it breaks any software (which I don't believe it does), it would only affect very new software. > >>>> > >>>> As I alluded to, I'd thought about perhaps adding a second node per interface so one would act as INTERRUPT transfers and the other as SET/GET_FEATURE transfers, but I already had this code half written and wanted to get feedback first, especially since what I have now works (although it's not well-tested after rebasing). > >>> > >>> I'm a little confused here about what you call an alternative mode. > >>> Are we talking about use_out_ep=1 (default behavior with INTERRUPT) > >>> or use_out_ep=0 (SETUP/SET_REPORT)? The last mode was added by me > >>> to ensure strict compatibility with Apple UEFI and strange BIOS, > >>> and this mode is actually actively used. It is important to me > >>> that it is not broken, but unfortunately I cannot test your patch > >>> on my kernel, as I temporarily do not have access to testing equipment. > >> > >> use_out_ep=0 is the alternate mode I was talking about. It didn't exist in 5.13, so as I said I wasn't aware of it until I rebased. As the device I'm using is still stuck on that old kernel (for now) and I don't know if I have any USB gadget capable devices on new kernels, I was unable to test it, and would very much like to make sure it doesn't regress before a patch is merged. I wasn't intending to break it, but I figured I'd get feedback I'd need to change before this was merged so if you could test it to ensure it doesn't regress any behavior that would be much appreciated and help me out. I will probably wait until then before submitting a v2. > > > > I will get access to the USB analyzer and test environment in about a month, > > if that suits you. You can write directly to my email after a month, > > I will help you with testing. > > I'm not in a huge rush, though I might try to find some hardware I can test a modern kernel on to help test. What are you running the kernel on? I'm using the Raspberry Pi 4 with Mac Mini as host (checking the OS, UEFI and Recovery mode).
Hi, On 7/31/22 01:14, Maxim Devaev wrote: > В Thu, 28 Jul 2022 11:11:31 -0700 > Vicki Pfau <vi@endrift.com> пишет: > >> On 7/28/22 01:59, Maxim Devaev wrote: >>> В Tue, 26 Jul 2022 21:26:05 -0700 >>> Vicki Pfau <vi@endrift.com> пишет: >>> >>>> On 7/26/22 02:51, Maxim Devaev wrote: >>>>> В Mon, 25 Jul 2022 17:58:26 -0700 >>>>> Vicki Pfau <vi@endrift.com> пишет: >>>>> >>>>>> While the HID gadget implementation has been sufficient for devices that only >>>>>> use INTERRUPT transfers, the USB HID standard includes provisions for Set- and >>>>>> Get-Feature report CONTROL transfers that go over endpoint 0. These were >>>>>> previously impossible with the existing implementation, and would either send >>>>>> an empty reply, or stall out. >>>>>> >>>>>> As the feature is a standard part of USB HID, it stands to reason that devices >>>>>> would use it, and that the HID gadget should support it. This patch adds >>>>>> support for host-to-device Set-Feature reports through a new ioctl >>>>>> interface to the hidg class dev nodes. >>>>>> >>>>>> Signed-off-by: Vicki Pfau <vi@endrift.com> >>>>> >>>>> Won't it break the logic of the existing software that works with /dev/hidgX? >>>>> Will it work if I want my gadget to work the old way? >>>> >>>> For existing software to use SET_FEATURE at all it has to use an alternative mode, which seems to have only been added somewhat recently. That mode also appears to preclude use of INTERRUPT transfers at all, unless there's some way to set up two hidg nodes that map to the same interface, with one for INTERRUPT and one for SET_FEATURE. If this breaks that, I suppose that's a regression, but this is meant to augment the original, long-standing mode so you can mix INTERRUPT and SET/GET_FEATURE transfers, as there is no way to do that yet. Honestly, the alternate mode seems more like a workaround, as far as I can tell, and not an ideal implementation. I'm not sure when it was added, but as I was originally authoring this against 5.13 and didn't see it until I went to rebase onto master, it can't have been that long ago. So if it breaks any software (which I don't believe it does), it would only affect very new software. >>>> >>>> As I alluded to, I'd thought about perhaps adding a second node per interface so one would act as INTERRUPT transfers and the other as SET/GET_FEATURE transfers, but I already had this code half written and wanted to get feedback first, especially since what I have now works (although it's not well-tested after rebasing). >>> >>> I'm a little confused here about what you call an alternative mode. >>> Are we talking about use_out_ep=1 (default behavior with INTERRUPT) >>> or use_out_ep=0 (SETUP/SET_REPORT)? The last mode was added by me >>> to ensure strict compatibility with Apple UEFI and strange BIOS, >>> and this mode is actually actively used. It is important to me >>> that it is not broken, but unfortunately I cannot test your patch >>> on my kernel, as I temporarily do not have access to testing equipment. >> >> use_out_ep=0 is the alternate mode I was talking about. It didn't exist in 5.13, so as I said I wasn't aware of it until I rebased. As the device I'm using is still stuck on that old kernel (for now) and I don't know if I have any USB gadget capable devices on new kernels, I was unable to test it, and would very much like to make sure it doesn't regress before a patch is merged. I wasn't intending to break it, but I figured I'd get feedback I'd need to change before this was merged so if you could test it to ensure it doesn't regress any behavior that would be much appreciated and help me out. I will probably wait until then before submitting a v2. > > I will get access to the USB analyzer and test environment in about a month, > if that suits you. You can write directly to my email after a month, > I will help you with testing. I wanted to check the status of this. We're in the middle of rebasing onto a newer kernel, so I might be able to test it myself soon. What software are you using?
В Thu, 8 Sep 2022 16:57:36 -0700 Vicki Pfau <vi@endrift.com> пишет: > Hi, > > On 7/31/22 01:14, Maxim Devaev wrote: > > В Thu, 28 Jul 2022 11:11:31 -0700 > > Vicki Pfau <vi@endrift.com> пишет: > > > >> On 7/28/22 01:59, Maxim Devaev wrote: > >>> В Tue, 26 Jul 2022 21:26:05 -0700 > >>> Vicki Pfau <vi@endrift.com> пишет: > >>> > >>>> On 7/26/22 02:51, Maxim Devaev wrote: > >>>>> В Mon, 25 Jul 2022 17:58:26 -0700 > >>>>> Vicki Pfau <vi@endrift.com> пишет: > >>>>> > >>>>>> While the HID gadget implementation has been sufficient for devices that only > >>>>>> use INTERRUPT transfers, the USB HID standard includes provisions for Set- and > >>>>>> Get-Feature report CONTROL transfers that go over endpoint 0. These were > >>>>>> previously impossible with the existing implementation, and would either send > >>>>>> an empty reply, or stall out. > >>>>>> > >>>>>> As the feature is a standard part of USB HID, it stands to reason that devices > >>>>>> would use it, and that the HID gadget should support it. This patch adds > >>>>>> support for host-to-device Set-Feature reports through a new ioctl > >>>>>> interface to the hidg class dev nodes. > >>>>>> > >>>>>> Signed-off-by: Vicki Pfau <vi@endrift.com> > >>>>> > >>>>> Won't it break the logic of the existing software that works with /dev/hidgX? > >>>>> Will it work if I want my gadget to work the old way? > >>>> > >>>> For existing software to use SET_FEATURE at all it has to use an alternative mode, which seems to have only been added somewhat recently. That mode also appears to preclude use of INTERRUPT transfers at all, unless there's some way to set up two hidg nodes that map to the same interface, with one for INTERRUPT and one for SET_FEATURE. If this breaks that, I suppose that's a regression, but this is meant to augment the original, long-standing mode so you can mix INTERRUPT and SET/GET_FEATURE transfers, as there is no way to do that yet. Honestly, the alternate mode seems more like a workaround, as far as I can tell, and not an ideal implementation. I'm not sure when it was added, but as I was originally authoring this against 5.13 and didn't see it until I went to rebase onto master, it can't have been that long ago. So if it breaks any software (which I don't believe it does), it would only affect very new software. > >>>> > >>>> As I alluded to, I'd thought about perhaps adding a second node per interface so one would act as INTERRUPT transfers and the other as SET/GET_FEATURE transfers, but I already had this code half written and wanted to get feedback first, especially since what I have now works (although it's not well-tested after rebasing). > >>> > >>> I'm a little confused here about what you call an alternative mode. > >>> Are we talking about use_out_ep=1 (default behavior with INTERRUPT) > >>> or use_out_ep=0 (SETUP/SET_REPORT)? The last mode was added by me > >>> to ensure strict compatibility with Apple UEFI and strange BIOS, > >>> and this mode is actually actively used. It is important to me > >>> that it is not broken, but unfortunately I cannot test your patch > >>> on my kernel, as I temporarily do not have access to testing equipment. > >> > >> use_out_ep=0 is the alternate mode I was talking about. It didn't exist in 5.13, so as I said I wasn't aware of it until I rebased. As the device I'm using is still stuck on that old kernel (for now) and I don't know if I have any USB gadget capable devices on new kernels, I was unable to test it, and would very much like to make sure it doesn't regress before a patch is merged. I wasn't intending to break it, but I figured I'd get feedback I'd need to change before this was merged so if you could test it to ensure it doesn't regress any behavior that would be much appreciated and help me out. I will probably wait until then before submitting a v2. > > > > I will get access to the USB analyzer and test environment in about a month, > > if that suits you. You can write directly to my email after a month, > > I will help you with testing. > > I wanted to check the status of this. We're in the middle of rebasing onto a newer kernel, so I might be able to test it myself soon. What software are you using? I'm using PiKVM on Raspberry Pi 4 (https://github.com/pikvm/pikvm) but for generic testing you need to make the usual ways of using gadget work in both modes: https://www.isticktoit.net/?p=1383 Unfortunately, I'm still away and I can't use my equipment :/
On 9/13/22 03:06, Maxim Devaev wrote: > В Thu, 8 Sep 2022 16:57:36 -0700 > Vicki Pfau <vi@endrift.com> пишет: > >> Hi, >> >> On 7/31/22 01:14, Maxim Devaev wrote: >>> В Thu, 28 Jul 2022 11:11:31 -0700 >>> Vicki Pfau <vi@endrift.com> пишет: >>> >>>> On 7/28/22 01:59, Maxim Devaev wrote: >>>>> В Tue, 26 Jul 2022 21:26:05 -0700 >>>>> Vicki Pfau <vi@endrift.com> пишет: >>>>> >>>>>> On 7/26/22 02:51, Maxim Devaev wrote: >>>>>>> В Mon, 25 Jul 2022 17:58:26 -0700 >>>>>>> Vicki Pfau <vi@endrift.com> пишет: >>>>>>> >>>>>>>> While the HID gadget implementation has been sufficient for devices that only >>>>>>>> use INTERRUPT transfers, the USB HID standard includes provisions for Set- and >>>>>>>> Get-Feature report CONTROL transfers that go over endpoint 0. These were >>>>>>>> previously impossible with the existing implementation, and would either send >>>>>>>> an empty reply, or stall out. >>>>>>>> >>>>>>>> As the feature is a standard part of USB HID, it stands to reason that devices >>>>>>>> would use it, and that the HID gadget should support it. This patch adds >>>>>>>> support for host-to-device Set-Feature reports through a new ioctl >>>>>>>> interface to the hidg class dev nodes. >>>>>>>> >>>>>>>> Signed-off-by: Vicki Pfau <vi@endrift.com> >>>>>>> >>>>>>> Won't it break the logic of the existing software that works with /dev/hidgX? >>>>>>> Will it work if I want my gadget to work the old way? >>>>>> >>>>>> For existing software to use SET_FEATURE at all it has to use an alternative mode, which seems to have only been added somewhat recently. That mode also appears to preclude use of INTERRUPT transfers at all, unless there's some way to set up two hidg nodes that map to the same interface, with one for INTERRUPT and one for SET_FEATURE. If this breaks that, I suppose that's a regression, but this is meant to augment the original, long-standing mode so you can mix INTERRUPT and SET/GET_FEATURE transfers, as there is no way to do that yet. Honestly, the alternate mode seems more like a workaround, as far as I can tell, and not an ideal implementation. I'm not sure when it was added, but as I was originally authoring this against 5.13 and didn't see it until I went to rebase onto master, it can't have been that long ago. So if it breaks any software (which I don't believe it does), it would only affect very new software. >>>>>> >>>>>> As I alluded to, I'd thought about perhaps adding a second node per interface so one would act as INTERRUPT transfers and the other as SET/GET_FEATURE transfers, but I already had this code half written and wanted to get feedback first, especially since what I have now works (although it's not well-tested after rebasing). >>>>> >>>>> I'm a little confused here about what you call an alternative mode. >>>>> Are we talking about use_out_ep=1 (default behavior with INTERRUPT) >>>>> or use_out_ep=0 (SETUP/SET_REPORT)? The last mode was added by me >>>>> to ensure strict compatibility with Apple UEFI and strange BIOS, >>>>> and this mode is actually actively used. It is important to me >>>>> that it is not broken, but unfortunately I cannot test your patch >>>>> on my kernel, as I temporarily do not have access to testing equipment. >>>> >>>> use_out_ep=0 is the alternate mode I was talking about. It didn't exist in 5.13, so as I said I wasn't aware of it until I rebased. As the device I'm using is still stuck on that old kernel (for now) and I don't know if I have any USB gadget capable devices on new kernels, I was unable to test it, and would very much like to make sure it doesn't regress before a patch is merged. I wasn't intending to break it, but I figured I'd get feedback I'd need to change before this was merged so if you could test it to ensure it doesn't regress any behavior that would be much appreciated and help me out. I will probably wait until then before submitting a v2. >>> >>> I will get access to the USB analyzer and test environment in about a month, >>> if that suits you. You can write directly to my email after a month, >>> I will help you with testing. >> >> I wanted to check the status of this. We're in the middle of rebasing onto a newer kernel, so I might be able to test it myself soon. What software are you using? > > I'm using PiKVM on Raspberry Pi 4 (https://github.com/pikvm/pikvm) but for generic testing you need to make > the usual ways of using gadget work in both modes: https://www.isticktoit.net/?p=1383 > Unfortunately, I'm still away and I can't use my equipment :/ I finally got a chance to test on 6.0, and I can confirm that it doesn't break use_out_ep=1 style read/write. You mention PiKVM, which I can test (I have a Pi 4 and bought the PiKVM v3 kit when it was on Kickstarter), but given that the lowest version of Linux it supports predates use_out_ep=0 style, I wasn't sure if that was sufficient to make sure I didn't break it. I'll prepare a v2 as soon as I can confirm how to test use_out_ep=0 style.
В Fri, 21 Oct 2022 17:28:25 -0700 Vicki Pfau <vi@endrift.com> пишет: > On 9/13/22 03:06, Maxim Devaev wrote: > > В Thu, 8 Sep 2022 16:57:36 -0700 > > Vicki Pfau <vi@endrift.com> пишет: > > > >> Hi, > >> > >> On 7/31/22 01:14, Maxim Devaev wrote: > >>> В Thu, 28 Jul 2022 11:11:31 -0700 > >>> Vicki Pfau <vi@endrift.com> пишет: > >>> > >>>> On 7/28/22 01:59, Maxim Devaev wrote: > >>>>> В Tue, 26 Jul 2022 21:26:05 -0700 > >>>>> Vicki Pfau <vi@endrift.com> пишет: > >>>>> > >>>>>> On 7/26/22 02:51, Maxim Devaev wrote: > >>>>>>> В Mon, 25 Jul 2022 17:58:26 -0700 > >>>>>>> Vicki Pfau <vi@endrift.com> пишет: > >>>>>>> > >>>>>>>> While the HID gadget implementation has been sufficient for devices that only > >>>>>>>> use INTERRUPT transfers, the USB HID standard includes provisions for Set- and > >>>>>>>> Get-Feature report CONTROL transfers that go over endpoint 0. These were > >>>>>>>> previously impossible with the existing implementation, and would either send > >>>>>>>> an empty reply, or stall out. > >>>>>>>> > >>>>>>>> As the feature is a standard part of USB HID, it stands to reason that devices > >>>>>>>> would use it, and that the HID gadget should support it. This patch adds > >>>>>>>> support for host-to-device Set-Feature reports through a new ioctl > >>>>>>>> interface to the hidg class dev nodes. > >>>>>>>> > >>>>>>>> Signed-off-by: Vicki Pfau <vi@endrift.com> > >>>>>>> > >>>>>>> Won't it break the logic of the existing software that works with /dev/hidgX? > >>>>>>> Will it work if I want my gadget to work the old way? > >>>>>> > >>>>>> For existing software to use SET_FEATURE at all it has to use an alternative mode, which seems to have only been added somewhat recently. That mode also appears to preclude use of INTERRUPT transfers at all, unless there's some way to set up two hidg nodes that map to the same interface, with one for INTERRUPT and one for SET_FEATURE. If this breaks that, I suppose that's a regression, but this is meant to augment the original, long-standing mode so you can mix INTERRUPT and SET/GET_FEATURE transfers, as there is no way to do that yet. Honestly, the alternate mode seems more like a workaround, as far as I can tell, and not an ideal implementation. I'm not sure when it was added, but as I was originally authoring this against 5.13 and didn't see it until I went to rebase onto master, it can't have been that long ago. So if it breaks any software (which I don't believe it does), it would only affect very new software. > >>>>>> > >>>>>> As I alluded to, I'd thought about perhaps adding a second node per interface so one would act as INTERRUPT transfers and the other as SET/GET_FEATURE transfers, but I already had this code half written and wanted to get feedback first, especially since what I have now works (although it's not well-tested after rebasing). > >>>>> > >>>>> I'm a little confused here about what you call an alternative mode. > >>>>> Are we talking about use_out_ep=1 (default behavior with INTERRUPT) > >>>>> or use_out_ep=0 (SETUP/SET_REPORT)? The last mode was added by me > >>>>> to ensure strict compatibility with Apple UEFI and strange BIOS, > >>>>> and this mode is actually actively used. It is important to me > >>>>> that it is not broken, but unfortunately I cannot test your patch > >>>>> on my kernel, as I temporarily do not have access to testing equipment. > >>>> > >>>> use_out_ep=0 is the alternate mode I was talking about. It didn't exist in 5.13, so as I said I wasn't aware of it until I rebased. As the device I'm using is still stuck on that old kernel (for now) and I don't know if I have any USB gadget capable devices on new kernels, I was unable to test it, and would very much like to make sure it doesn't regress before a patch is merged. I wasn't intending to break it, but I figured I'd get feedback I'd need to change before this was merged so if you could test it to ensure it doesn't regress any behavior that would be much appreciated and help me out. I will probably wait until then before submitting a v2. > >>> > >>> I will get access to the USB analyzer and test environment in about a month, > >>> if that suits you. You can write directly to my email after a month, > >>> I will help you with testing. > >> > >> I wanted to check the status of this. We're in the middle of rebasing onto a newer kernel, so I might be able to test it myself soon. What software are you using? > > > > I'm using PiKVM on Raspberry Pi 4 (https://github.com/pikvm/pikvm) but for generic testing you need to make > > the usual ways of using gadget work in both modes: https://www.isticktoit.net/?p=1383 > > Unfortunately, I'm still away and I can't use my equipment :/ > > I finally got a chance to test on 6.0, and I can confirm that it doesn't break use_out_ep=1 style read/write. You mention PiKVM, which I can test (I have a Pi 4 and bought the PiKVM v3 kit when it was on Kickstarter), but given that the lowest version of Linux it supports predates use_out_ep=0 style, I wasn't sure if that was sufficient to make sure I didn't break it. I'll prepare a v2 as soon as I can confirm how to test use_out_ep=0 style. Sounds great! BTW PiKVM uses 5.15 LTS kernel from Raspberry Pi repo with several patches. use_out_ep works there. https://github.com/raspberrypi/linux
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 7e70e4a168e6..97aa56206020 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -72,6 +72,11 @@ struct f_hidg { wait_queue_head_t write_queue; struct usb_request *req; + /* set report */ + struct list_head completed_set_req; + spinlock_t set_spinlock; + wait_queue_head_t set_queue; + /* get report */ struct usb_request *get_req; struct usb_hidg_report get_report; @@ -519,6 +524,54 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, return status; } +static int f_hidg_set_report(struct file *file, struct usb_hidg_report __user *buffer) +{ + struct f_hidg *hidg = file->private_data; + struct f_hidg_req_list *list; + struct usb_request *req; + unsigned long flags; + unsigned short length; + int status; + + spin_lock_irqsave(&hidg->set_spinlock, flags); + +#define SET_REPORT_COND (!list_empty(&hidg->completed_set_req)) + + /* wait for at least one buffer to complete */ + while (!SET_REPORT_COND) { + spin_unlock_irqrestore(&hidg->set_spinlock, flags); + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (wait_event_interruptible(hidg->set_queue, SET_REPORT_COND)) + return -ERESTARTSYS; + + spin_lock_irqsave(&hidg->set_spinlock, flags); + } + + /* pick the first one */ + list = list_first_entry(&hidg->completed_set_req, + struct f_hidg_req_list, list); + + /* + * Remove this from list to protect it from being free() + * while host disables our function + */ + list_del(&list->list); + + req = list->req; + spin_unlock_irqrestore(&hidg->set_spinlock, flags); + + /* copy to user outside spinlock */ + length = min_t(unsigned short, sizeof(buffer->data), req->actual); + status = copy_to_user(&buffer->length, &length, sizeof(buffer->length)); + if (!status) { + status = copy_to_user(&buffer->data, req->buf, length); + } + kfree(list); + free_ep_req(hidg->func.config->cdev->gadget->ep0, req); + return status; +} static int f_hidg_get_report(struct file *file, struct usb_hidg_report __user *buffer) { @@ -570,6 +623,8 @@ static int f_hidg_get_report(struct file *file, struct usb_hidg_report __user *b static long f_hidg_ioctl(struct file *file, unsigned int code, unsigned long arg) { switch (code) { + case GADGET_HID_READ_SET_REPORT: + return f_hidg_set_report(file, (struct usb_hidg_report __user *)arg); case GADGET_HID_WRITE_GET_REPORT: return f_hidg_get_report(file, (struct usb_hidg_report __user *)arg); default: @@ -584,6 +639,7 @@ static __poll_t f_hidg_poll(struct file *file, poll_table *wait) poll_wait(file, &hidg->read_queue, wait); poll_wait(file, &hidg->write_queue, wait); + poll_wait(file, &hidg->set_queue, wait); if (WRITE_COND) ret |= EPOLLOUT | EPOLLWRNORM; @@ -596,12 +652,16 @@ static __poll_t f_hidg_poll(struct file *file, poll_table *wait) ret |= EPOLLIN | EPOLLRDNORM; } + if (SET_REPORT_COND) + ret |= EPOLLPRI; + return ret; } #undef WRITE_COND #undef READ_COND_SSREPORT #undef READ_COND_INTOUT +#undef SET_REPORT_COND #undef GET_REPORT_COND static int f_hidg_release(struct inode *inode, struct file *fd) @@ -646,11 +706,19 @@ static void hidg_intout_complete(struct usb_ep *ep, struct usb_request *req) req_list->req = req; - spin_lock_irqsave(&hidg->read_spinlock, flags); - list_add_tail(&req_list->list, &hidg->completed_out_req); - spin_unlock_irqrestore(&hidg->read_spinlock, flags); + if (ep == cdev->gadget->ep0) { + spin_lock_irqsave(&hidg->set_spinlock, flags); + list_add_tail(&req_list->list, &hidg->completed_set_req); + spin_unlock_irqrestore(&hidg->set_spinlock, flags); - wake_up(&hidg->read_queue); + wake_up(&hidg->set_queue); + } else { + spin_lock_irqsave(&hidg->read_spinlock, flags); + list_add_tail(&req_list->list, &hidg->completed_out_req); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); + + wake_up(&hidg->read_queue); + } break; default: ERROR(cdev, "Set report failed %d\n", req->status); @@ -763,12 +831,29 @@ static int hidg_setup(struct usb_function *f, case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_SET_REPORT): VDBG(cdev, "set_report | wLength=%d\n", ctrl->wLength); - if (hidg->use_out_ep) + if (!hidg->use_out_ep) { + req->complete = hidg_ssreport_complete; + req->context = hidg; + goto respond; + } + if (!length) { goto stall; - req->complete = hidg_ssreport_complete; + } + req = alloc_ep_req(cdev->gadget->ep0, GFP_ATOMIC); + if (!req) { + return -ENOMEM; + } + req->complete = hidg_intout_complete; req->context = hidg; - goto respond; - break; + req->zero = 0; + req->length = length; + status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); + if (status < 0) { + ERROR(cdev, "usb_ep_queue error on set_report %d\n", status); + free_ep_req(cdev->gadget->ep0, req); + } + + return status; case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | HID_REQ_SET_PROTOCOL): @@ -868,6 +953,14 @@ static void hidg_disable(struct usb_function *f) spin_unlock_irqrestore(&hidg->read_spinlock, flags); } + spin_lock_irqsave(&hidg->set_spinlock, flags); + list_for_each_entry_safe(list, next, &hidg->completed_set_req, list) { + free_ep_req(f->config->cdev->gadget->ep0, list->req); + list_del(&list->list); + kfree(list); + } + spin_unlock_irqrestore(&hidg->set_spinlock, flags); + spin_lock_irqsave(&hidg->write_spinlock, flags); if (!hidg->write_pending) { free_ep_req(hidg->in_ep, hidg->req); @@ -1098,11 +1191,14 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg->write_pending = 1; hidg->req = NULL; spin_lock_init(&hidg->read_spinlock); + spin_lock_init(&hidg->set_spinlock); spin_lock_init(&hidg->get_spinlock); init_waitqueue_head(&hidg->write_queue); init_waitqueue_head(&hidg->read_queue); + init_waitqueue_head(&hidg->set_queue); init_waitqueue_head(&hidg->get_queue); INIT_LIST_HEAD(&hidg->completed_out_req); + INIT_LIST_HEAD(&hidg->completed_set_req); /* create char device */ cdev_init(&hidg->cdev, &f_hidg_fops); diff --git a/include/uapi/linux/usb/g_hid.h b/include/uapi/linux/usb/g_hid.h index c6068b486354..81416698e145 100644 --- a/include/uapi/linux/usb/g_hid.h +++ b/include/uapi/linux/usb/g_hid.h @@ -33,6 +33,7 @@ struct usb_hidg_report { * Don't add any colliding codes to either driver, and keep * them in unique ranges (size 0x20 for now). */ +#define GADGET_HID_READ_SET_REPORT _IOR('g', 0x41, struct usb_hidg_report) #define GADGET_HID_WRITE_GET_REPORT _IOW('g', 0x42, struct usb_hidg_report) #endif /* __UAPI_LINUX_USB_G_HID_H */
While the HID gadget implementation has been sufficient for devices that only use INTERRUPT transfers, the USB HID standard includes provisions for Set- and Get-Feature report CONTROL transfers that go over endpoint 0. These were previously impossible with the existing implementation, and would either send an empty reply, or stall out. As the feature is a standard part of USB HID, it stands to reason that devices would use it, and that the HID gadget should support it. This patch adds support for host-to-device Set-Feature reports through a new ioctl interface to the hidg class dev nodes. Signed-off-by: Vicki Pfau <vi@endrift.com> --- drivers/usb/gadget/function/f_hid.c | 112 ++++++++++++++++++++++++++-- include/uapi/linux/usb/g_hid.h | 1 + 2 files changed, 105 insertions(+), 8 deletions(-)