[PATCH] usb: core: message: remove extra endianness conversion in usb_set_isoch_delay
No need to do extra endianness conversion in usb_set_isoch_delay because it is already done in usb_control_msg() Fixes: 886ee36e7205 ("usb: core: add support for USB_REQ_SET_ISOCH_DELAY") Cc: Dmytro Panchenko <dmytro.panche...@globallogic.com> Cc: Felipe Balbi <felipe.ba...@linux.intel.com> Cc: stable <sta...@vger.kernel.org> # v4.16+ Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/core/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 0c11d40..7b13700 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -940,7 +940,7 @@ int usb_set_isoch_delay(struct usb_device *dev) return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_ISOCH_DELAY, USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, - cpu_to_le16(dev->hub_delay), 0, NULL, 0, + dev->hub_delay, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); } -- 1.9.1 -- 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/1] USB Audio Device Class 3.0 Gadget support
Hi Felipe, On Mon, Dec 4, 2017 at 1:36 PM, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Ruslan Bilovol <ruslan.bilo...@gmail.com> writes: >> On Tue, Nov 7, 2017 at 3:52 AM, Ruslan Bilovol <ruslan.bilo...@gmail.com> >> wrote: >>> Hi, >>> >>> This patch adds USB Audio Device Class 3.0 [1] function >>> support to gadget subsystem. >>> I didn't add UAC3 support to legacy gadget as it will >>> make preprocessor configuration too complex (UAC3 device >>> must have two configurations for backward compatibility, >>> first is UAC1/2 and second is UAC3), yet also I'm too lazy >>> to do that and verify all possible configurations. >>> >>> For modern ConfigFS interface I'll provide my configuration >>> for testing below; testing was done on a BeagleBone Black >>> board. >>> >>> This patch depends on uac3 header files from include dir >>> which I'll post as part of ALSA host UAC3 patch and will >>> provide the link to it here. >> >> http://www.spinics.net/lists/alsa-devel/msg69071.html > > Once that patch hits upstream, then we can queue this for merge window > otherwise we will just have issues and create unbisectable points in the > tree. Takashi promised to create an immutable branch for that purpose. However, I'm currently reworking configfs part of UAC3 for channels configuration handling, which is now more clear after sharing missing parts of UAC3 spec by Pierre-Louis Bossart during host side patches review; so I will send v2 soon. Thanks, Ruslan -- 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/1] USB Audio Device Class 3.0 Gadget support
On Tue, Nov 7, 2017 at 3:52 AM, Ruslan Bilovol <ruslan.bilo...@gmail.com> wrote: > Hi, > > This patch adds USB Audio Device Class 3.0 [1] function > support to gadget subsystem. > I didn't add UAC3 support to legacy gadget as it will > make preprocessor configuration too complex (UAC3 device > must have two configurations for backward compatibility, > first is UAC1/2 and second is UAC3), yet also I'm too lazy > to do that and verify all possible configurations. > > For modern ConfigFS interface I'll provide my configuration > for testing below; testing was done on a BeagleBone Black > board. > > This patch depends on uac3 header files from include dir > which I'll post as part of ALSA host UAC3 patch and will > provide the link to it here. http://www.spinics.net/lists/alsa-devel/msg69071.html Thanks, Ruslan -- 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 0/1] USB Audio Device Class 3.0 Gadget support
Hi, This patch adds USB Audio Device Class 3.0 [1] function support to gadget subsystem. I didn't add UAC3 support to legacy gadget as it will make preprocessor configuration too complex (UAC3 device must have two configurations for backward compatibility, first is UAC1/2 and second is UAC3), yet also I'm too lazy to do that and verify all possible configurations. For modern ConfigFS interface I'll provide my configuration for testing below; testing was done on a BeagleBone Black board. This patch depends on uac3 header files from include dir which I'll post as part of ALSA host UAC3 patch and will provide the link to it here. uac_3 mkdir cfg mount none cfg -t configfs mkdir cfg/usb_gadget/g1 cd cfg/usb_gadget/g1 mkdir configs/c.1 mkdir functions/uac3.0 mkdir strings/0x409 mkdir configs/c.1/strings/0x409 echo 0x0101 > idProduct echo 0x1d6b > idVendor echo my-serial-num > strings/0x409/serialnumber echo my-manufacturer > strings/0x409/manufacturer echo "Test gadget" > strings/0x409/product echo "Conf 1" > configs/c.1/strings/0x409/configuration echo 120 > configs/c.1/MaxPower ln -s functions/uac3.0 configs/c.1 echo musb-hdrc.0 > UDC uac_3 + uac2 mkdir cfg mount none cfg -t configfs mkdir cfg/usb_gadget/g1 cd cfg/usb_gadget/g1 mkdir configs/c.1 mkdir functions/uac2.0 mkdir strings/0x409 mkdir configs/c.1/strings/0x409 echo "Test gadget" > strings/0x409/product echo "Conf 1" > configs/c.1/strings/0x409/configuration echo 120 > configs/c.1/MaxPower ln -s functions/uac2.0 configs/c.1 mkdir configs/c.2 mkdir functions/uac3.0 mkdir strings/0x409 mkdir configs/c.2/strings/0x409 echo "Conf 2" > configs/c.2/strings/0x409/configuration echo 120 > configs/c.2/MaxPower ln -s functions/uac3.0 configs/c.2 echo 0x0101 > idProduct echo 0x1d6b > idVendor echo my-serial-num > strings/0x409/serialnumber echo my-manufacturer > strings/0x409/manufacturer echo musb-hdrc.0 > UDC [1] http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip Ruslan Bilovol (1): usb: gadget: add USB Audio Device Class 3.0 gadget support Documentation/ABI/testing/configfs-usb-gadget-uac3 | 14 + Documentation/usb/gadget-testing.txt | 41 + drivers/usb/gadget/Kconfig | 22 + drivers/usb/gadget/function/Makefile |2 + drivers/usb/gadget/function/f_uac3.c | 1497 drivers/usb/gadget/function/u_uac3.h | 38 + drivers/usb/gadget/legacy/Kconfig |3 +- 7 files changed, 1616 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac3 create mode 100644 drivers/usb/gadget/function/f_uac3.c create mode 100644 drivers/usb/gadget/function/u_uac3.h -- 1.9.1 -- 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 1/1] usb: gadget: add USB Audio Device Class 3.0 gadget support
Recently released USB Audio Class 3.0 specification introduces many significant changes comparing to previous versions, like - new Power Domains, support for LPM/L1 - new Cluster descriptor - changed layout of all class-specific descriptors - new High Capability descriptors - New class-specific String descriptors - new and removed units - additional sources for interrupts - removed Type II Audio Data Formats - ... and many other things (check spec) It also provides backward compatibility through multiple configurations, as well as requires mandatory support for BADD (Basic Audio Device Definition) on each ADC3.0 compliant device This patch adds UAC3 gadget support basing on UAC3 specification, implementing Generic I/O Profile (BAOF + BAIF) from BADD document. There are still few areas for future improvements because not all functionality is completely implemented, for example volume, mute and power management handling has dummy implementation in some places Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- Documentation/ABI/testing/configfs-usb-gadget-uac3 | 14 + Documentation/usb/gadget-testing.txt | 41 + drivers/usb/gadget/Kconfig | 22 + drivers/usb/gadget/function/Makefile |2 + drivers/usb/gadget/function/f_uac3.c | 1497 drivers/usb/gadget/function/u_uac3.h | 38 + drivers/usb/gadget/legacy/Kconfig |3 +- 7 files changed, 1616 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac3 create mode 100644 drivers/usb/gadget/function/f_uac3.c create mode 100644 drivers/usb/gadget/function/u_uac3.h diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac3 b/Documentation/ABI/testing/configfs-usb-gadget-uac3 new file mode 100644 index 000..54bb00e --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-uac3 @@ -0,0 +1,14 @@ +What: /config/usb-gadget/gadget/functions/uac3.name +Date: Nov 2017 +KernelVersion: 4.16 +Description: + The attributes: + + c_chmask - capture channel mask + c_srate - capture sampling rate + c_ssize - capture sample size (bytes) + p_chmask - playback channel mask + p_srate - playback sampling rate + p_ssize - playback sample size (bytes) + req_number - the number of pre-allocated request + for both capture and playback diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index fbc397d..36d5e2b 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -21,6 +21,7 @@ provided by gadgets. 18. UVC function 19. PRINTER function 20. UAC1 function (new API) +21. UAC3 function 1. ACM function @@ -817,3 +818,43 @@ e.g.: $ arecord -f dat -t wav -D hw:CARD=UAC1Gadget,DEV=0 | \ aplay -D default:CARD=OdroidU3 + +21. UAC3 function += + +The function is provided by usb_f_uac3.ko module. + +Function-specific configfs interface + + +The function name to use when creating the function directory is "uac3". +The uac3 function provides these attributes in its function directory: + + c_chmask - capture channel mask + c_srate - capture sampling rate + c_ssize - capture sample size (bytes) + p_chmask - playback channel mask + p_srate - playback sampling rate + p_ssize - playback sample size (bytes) + req_number - the number of pre-allocated request for both capture +and playback + +The attributes have sane default values. + +Testing the UAC3 function +- + +device: run the gadget +host: aplay -l # should list our USB Audio Gadget + +This function does not require real hardware support, it just +sends a stream of audio data to/from the host. In order to +actually hear something at the device side, a command similar +to this must be used at the device side: + +$ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 & + +e.g.: + +$ arecord -f dat -t wav -D hw:CARD=UAC3Gadget,DEV=0 | \ +aplay -D default:CARD=OdroidU3 diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 31cce78..d53ae7d 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -200,6 +200,9 @@ config USB_F_UAC1_LEGACY config USB_F_UAC2 tristate +config USB_F_UAC3 + tristate + config USB_F_UVC tristate @@ -418,6 +421,25 @@ config USB_CONFIGFS_F_UAC2 received from the USB Host and choose to provide whatever it wants as audio data to the USB Host. +config USB_CONFIGFS_F_UAC3 + bool "Audio Class 3.0" + depends on USB_CONFIGFS + depends on SND + select USB_LIBCOMPOSITE + select SND_PCM + select USB_U_A
[PATCH 1/3] include: usb: audio: specify exact endiannes of descriptors
USB spec says that multiple byte fields are stored in little-endian order (see chapter 8.1 of USB2.0 spec and chapter 7.1 of USB3.0 spec), thus mark such fields as LE for UAC1 and UAC2 headers Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- include/linux/usb/audio-v2.h | 14 +++--- include/uapi/linux/usb/audio.h | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index c5f2158..fd73bc0 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h @@ -115,13 +115,13 @@ struct uac2_input_terminal_descriptor { __u8 bDescriptorType; __u8 bDescriptorSubtype; __u8 bTerminalID; - __u16 wTerminalType; + __le16 wTerminalType; __u8 bAssocTerminal; __u8 bCSourceID; __u8 bNrChannels; - __u32 bmChannelConfig; + __le32 bmChannelConfig; __u8 iChannelNames; - __u16 bmControls; + __le16 bmControls; __u8 iTerminal; } __attribute__((packed)); @@ -132,11 +132,11 @@ struct uac2_output_terminal_descriptor { __u8 bDescriptorType; __u8 bDescriptorSubtype; __u8 bTerminalID; - __u16 wTerminalType; + __le16 wTerminalType; __u8 bAssocTerminal; __u8 bSourceID; __u8 bCSourceID; - __u16 bmControls; + __le16 bmControls; __u8 iTerminal; } __attribute__((packed)); @@ -164,9 +164,9 @@ struct uac2_as_header_descriptor { __u8 bTerminalLink; __u8 bmControls; __u8 bFormatType; - __u32 bmFormats; + __le32 bmFormats; __u8 bNrChannels; - __u32 bmChannelConfig; + __le32 bmChannelConfig; __u8 iChannelNames; } __attribute__((packed)); diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h index d2314be..a4680a5 100644 --- a/include/uapi/linux/usb/audio.h +++ b/include/uapi/linux/usb/audio.h @@ -333,7 +333,7 @@ struct uac_processing_unit_descriptor { __u8 bDescriptorType; __u8 bDescriptorSubtype; __u8 bUnitID; - __u16 wProcessType; + __le16 wProcessType; __u8 bNrInPins; __u8 baSourceID[]; } __attribute__ ((packed)); @@ -491,8 +491,8 @@ struct uac_format_type_ii_ext_descriptor { __u8 bDescriptorType; __u8 bDescriptorSubtype; __u8 bFormatType; - __u16 wMaxBitRate; - __u16 wSamplesPerFrame; + __le16 wMaxBitRate; + __le16 wSamplesPerFrame; __u8 bHeaderLength; __u8 bSideBandProtocol; } __attribute__((packed)); -- 1.9.1 -- 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 2/3] usb: gadget: f_uac1: endianness fixes.
As per USB spec, multiple-bytes fields are stored in little-endian order. Use CPU<->LE helpers for such fields. Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/function/f_uac1.c | 20 ++-- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 8656f84..29efbed 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -92,9 +92,9 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f) .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, .bTerminalID = USB_OUT_IT_ID, - .wTerminalType =UAC_TERMINAL_STREAMING, + .wTerminalType =cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, - .wChannelConfig = 0x3, + .wChannelConfig = cpu_to_le16(0x3), }; #define IO_OUT_OT_ID 2 @@ -103,7 +103,7 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f) .bDescriptorType= USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, .bTerminalID= IO_OUT_OT_ID, - .wTerminalType = UAC_OUTPUT_TERMINAL_SPEAKER, + .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER), .bAssocTerminal = 0, .bSourceID = USB_OUT_IT_ID, }; @@ -114,9 +114,9 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f) .bDescriptorType= USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, .bTerminalID= IO_IN_IT_ID, - .wTerminalType = UAC_INPUT_TERMINAL_MICROPHONE, + .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE), .bAssocTerminal = 0, - .wChannelConfig = 0x3, + .wChannelConfig = cpu_to_le16(0x3), }; #define USB_IN_OT_ID 4 @@ -125,7 +125,7 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f) .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, .bTerminalID = USB_IN_OT_ID, - .wTerminalType =UAC_TERMINAL_STREAMING, + .wTerminalType =cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, .bSourceID =IO_IN_IT_ID, }; @@ -174,7 +174,7 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f) .bDescriptorSubtype = UAC_AS_GENERAL, .bTerminalLink =USB_OUT_IT_ID, .bDelay = 1, - .wFormatTag = UAC_FORMAT_TYPE_I_PCM, + .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), }; static struct uac1_as_header_descriptor as_in_header_desc = { @@ -183,7 +183,7 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f) .bDescriptorSubtype = UAC_AS_GENERAL, .bTerminalLink =USB_IN_OT_ID, .bDelay = 1, - .wFormatTag = UAC_FORMAT_TYPE_I_PCM, + .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), }; DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1); @@ -606,8 +606,8 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) if (status) goto fail; - audio->out_ep_maxpsize = as_out_ep_desc.wMaxPacketSize; - audio->in_ep_maxpsize = as_in_ep_desc.wMaxPacketSize; + audio->out_ep_maxpsize = le16_to_cpu(as_out_ep_desc.wMaxPacketSize); + audio->in_ep_maxpsize = le16_to_cpu(as_in_ep_desc.wMaxPacketSize); audio->params.c_chmask = audio_opts->c_chmask; audio->params.c_srate = audio_opts->c_srate; audio->params.c_ssize = audio_opts->c_ssize; -- 1.9.1 -- 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 0/3] USB Audio gadget endianness fixes
Audio gadget refactoring patches touched few function files and triggered kbuild test robot verification who found some endianness issues by sparse tool. Since most of these issues existed from beginning in f_uac2 and f_uac1_legacy drivers (and were inherited be f_uac1), it seems nobody run audio gadgets on big-endian systems. I fixed only f_uac1/f_uac2 issues leaving leagacy uac1 driver untouched. USB audio headers also were updated. I tested patches only on LE system because I have no big-endian hardware. Also there is no anymore endianness warnings from sparse during kernel build. For big endian case tested only build which also doesn't produce sparse warnings anymore. Ruslan Bilovol (3): include: usb: audio: specify exact endiannes of descriptors usb: gadget: f_uac1: endianness fixes. usb: gadget: f_uac2: endianness fixes. drivers/usb/gadget/function/f_uac1.c | 20 ++-- drivers/usb/gadget/function/f_uac2.c | 25 ++--- include/linux/usb/audio-v2.h | 14 +++--- include/uapi/linux/usb/audio.h | 6 +++--- 4 files changed, 34 insertions(+), 31 deletions(-) -- 1.9.1 -- 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 3/3] usb: gadget: f_uac2: endianness fixes.
As per USB spec, multiple-bytes fields are stored in little-endian order. Use CPU<->LE helpers for such fields. Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/function/f_uac2.c | 25 ++--- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 9082ce2..f05c3f3 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -168,7 +168,7 @@ enum { .bAssocTerminal = 0, .bCSourceID = USB_OUT_CLK_ID, .iChannelNames = 0, - .bmControls = (CONTROL_RDWR << COPY_CTRL), + .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; /* Input Terminal for I/O-In */ @@ -182,7 +182,7 @@ enum { .bAssocTerminal = 0, .bCSourceID = USB_IN_CLK_ID, .iChannelNames = 0, - .bmControls = (CONTROL_RDWR << COPY_CTRL), + .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; /* Ouput Terminal for USB_IN */ @@ -196,7 +196,7 @@ enum { .bAssocTerminal = 0, .bSourceID = IO_IN_IT_ID, .bCSourceID = USB_IN_CLK_ID, - .bmControls = (CONTROL_RDWR << COPY_CTRL), + .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; /* Ouput Terminal for I/O-Out */ @@ -210,7 +210,7 @@ enum { .bAssocTerminal = 0, .bSourceID = USB_OUT_IT_ID, .bCSourceID = USB_OUT_CLK_ID, - .bmControls = (CONTROL_RDWR << COPY_CTRL), + .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; static struct uac2_ac_header_descriptor ac_hdr_desc = { @@ -220,9 +220,10 @@ enum { .bDescriptorSubtype = UAC_MS_HEADER, .bcdADC = cpu_to_le16(0x200), .bCategory = UAC2_FUNCTION_IO_BOX, - .wTotalLength = sizeof in_clk_src_desc + sizeof out_clk_src_desc -+ sizeof usb_out_it_desc + sizeof io_in_it_desc - + sizeof usb_in_ot_desc + sizeof io_out_ot_desc, + .wTotalLength = cpu_to_le16(sizeof in_clk_src_desc + + sizeof out_clk_src_desc + sizeof usb_out_it_desc + + sizeof io_in_it_desc + sizeof usb_in_ot_desc + + sizeof io_out_ot_desc), .bmControls = 0, }; @@ -569,10 +570,12 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, return ret; } - agdev->in_ep_maxpsize = max(fs_epin_desc.wMaxPacketSize, - hs_epin_desc.wMaxPacketSize); - agdev->out_ep_maxpsize = max(fs_epout_desc.wMaxPacketSize, - hs_epout_desc.wMaxPacketSize); + agdev->in_ep_maxpsize = max_t(u16, + le16_to_cpu(fs_epin_desc.wMaxPacketSize), + le16_to_cpu(hs_epin_desc.wMaxPacketSize)); + agdev->out_ep_maxpsize = max_t(u16, + le16_to_cpu(fs_epout_desc.wMaxPacketSize), + le16_to_cpu(hs_epout_desc.wMaxPacketSize)); hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; -- 1.9.1 -- 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 v5 0/4] USB Audio Gadget refactoring
Hi Felipe, This is v5 of audio gadget refactoring. Note, that legacy f_uac1 function is broken since v4.10 by commit 7e4da3fcf7c9 ("usb: gadget: composite: Test get_alt() presence instead of set_alt()"). The fact that at v4.12-rc5 time nobody cares about may be a good sign that number of users is small if any. Thus making it legacy makes sence. This series depends on legacy f_uac1 fix I posted before: http://www.spinics.net/lists/linux-usb/msg158373.html Without this fix it's not possible to check that refactoring didn't break legacy f_uac1 functionality I came to this patch series when wanted to do two things: - use UAC1 as virtual ALSA sound card on gadget side, just like UAC2 is used so it's possible to do rate resampling - have both playback/capture support in UAC1 Since I wanted to have same behavior for both UAC1/UAC2, obviously I've got an utility part (u_audio.c) for virtual ALSA sound card handling like we have for ethernet(u_ether) or serial(u_serial) functions. Function-specific parts (f_uac1/f_uac2) became almost as storage for class-specific USB descriptors, some boilerplate for configfs, binding and few USB config request handling. Originally in RFC [1] I've posted before, there was major change to f_uac1 after that it couldn't do direct play to existing ALSA sound card anymore, representing audio on gadget side as virtual ALSA sound card where audio streams are simply sinked to and sourced from it, so it may break current usecase for some people (and that's why it was RFC). During RFC discussion, it was agreed to not touch existing f_uac1 implementation and create new one instead. At v4 patchet discussion another approach was agreed - current f_uac1.c gets renamed to f_uac1_legacy.c and introduced a *new* f_uac1.c instead that is done in current patchset (v5) Now, it's possible to use existing user-space applications for audio routing between Audio Gadget and real sound card. I personally use alsaloop tool from alsautils and have ability to create PCM loopback between two different ALSA cards using rate resampling, which was not possible with previous "direct play to ALSA card" approach in f_uac1. While here, also dropped redundant platform driver/device creation in f_uac2 driver (as well as didn't add "never implemented" volume/mute functionality in f_uac1_legacy to f_uac1) that made this work even easier to do. This series is tested with both legacy g_audio.ko and modern configfs approaches under Ubuntu 14.04 (UAC1 and UAC2) and under Windows7 x64 (UAC1 only) having perfect results in all cases. Comments, testing are welcome. v5 changes: - after discussion with Felipe, switched to another approach with making current f_uac1 legacy and introducing a new f_uac1.c instead - addressed Jassi's copyright comments v4 changes: - renamed f_uac1_newapi to f_uac1_acard that is more meaningful - rebased on top of balbi/next v3 changes: - renamed u_audio exported symbols so they don't conflict with old f_uac1 if both are built-in. v2 changes: - do not touch f_uac1, instead created f_uac1_newapi - added documentation for f_uac1_newapi - rebased on top of v4.8-rc1 [1] https://lkml.org/lkml/2016/5/23/649 Ruslan Bilovol (4): usb: gadget: f_uac2: remove platform driver/device creation usb: gadget: f_uac2: split out audio core usb: gadget: function: make current f_uac1 implementation legacy usb: gadget: add f_uac1 variant based on a new u_audio api Documentation/ABI/testing/configfs-usb-gadget-uac1 | 18 +- .../ABI/testing/configfs-usb-gadget-uac1_legacy| 12 + Documentation/usb/gadget-testing.txt | 53 +- drivers/usb/gadget/Kconfig | 29 +- drivers/usb/gadget/function/Makefile |5 +- drivers/usb/gadget/function/f_uac1.c | 906 +++-- drivers/usb/gadget/function/f_uac1_legacy.c| 1021 drivers/usb/gadget/function/f_uac2.c | 795 ++- drivers/usb/gadget/function/u_audio.c | 662 + drivers/usb/gadget/function/u_audio.h | 95 ++ drivers/usb/gadget/function/u_uac1.h | 87 +- .../gadget/function/{u_uac1.c => u_uac1_legacy.c} |7 +- drivers/usb/gadget/function/u_uac1_legacy.h| 82 ++ drivers/usb/gadget/legacy/Kconfig | 15 +- drivers/usb/gadget/legacy/audio.c | 55 +- 15 files changed, 2494 insertions(+), 1348 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac1_legacy create mode 100644 drivers/usb/gadget/function/f_uac1_legacy.c create mode 100644 drivers/usb/gadget/function/u_audio.c create mode 100644 drivers/usb/gadget/function/u_audio.h rename drivers/usb/gadget/function/{u_uac1.c => u_uac1_legacy.c} (98%) create mode 100644 drivers/usb/gadget/function/u_uac1_legacy.h -- 1.9.1 --
[PATCH v5 1/4] usb: gadget: f_uac2: remove platform driver/device creation
Simplify f_uac2 by removing platform driver/device creation; use composite's usb_gadget device as parent for sound card and for debug prints. This removes extra layer of code without any functional change. Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/function/f_uac2.c | 107 +-- 1 file changed, 28 insertions(+), 79 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 5a7ba05..f674bae 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -13,7 +13,6 @@ #include #include -#include #include #include @@ -51,8 +50,6 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -static const char *uac2_name = "snd_uac2"; - struct uac2_req { struct uac2_rtd_params *pp; /* parent param */ struct usb_request *req; @@ -81,9 +78,6 @@ struct uac2_rtd_params { }; struct snd_uac2_chip { - struct platform_device pdev; - struct platform_driver pdrv; - struct uac2_rtd_params p_prm; struct uac2_rtd_params c_prm; @@ -122,6 +116,7 @@ struct audio_dev { struct usb_ep *in_ep, *out_ep; struct usb_function func; + struct usb_gadget *gadget; /* The ALSA Sound Card it represents on the USB-Client side */ struct snd_uac2_chip uac2; @@ -140,12 +135,6 @@ struct audio_dev *uac2_to_agdev(struct snd_uac2_chip *u) } static inline -struct snd_uac2_chip *pdev_to_uac2(struct platform_device *p) -{ - return container_of(p, struct snd_uac2_chip, pdev); -} - -static inline struct f_uac2_opts *agdev_to_uac2_opts(struct audio_dev *agdev) { return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); @@ -254,7 +243,7 @@ uint num_channels(uint chanmask) exit: if (usb_ep_queue(ep, req, GFP_ATOMIC)) - dev_err(>pdev.dev, "%d Error!\n", __LINE__); + dev_err(uac2->card->dev, "%d Error!\n", __LINE__); if (update_alsa) snd_pcm_period_elapsed(substream); @@ -440,23 +429,22 @@ static int uac2_pcm_null(struct snd_pcm_substream *substream) .prepare = uac2_pcm_null, }; -static int snd_uac2_probe(struct platform_device *pdev) +static int snd_uac2_probe(struct audio_dev *audio_dev) { - struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev); + struct snd_uac2_chip *uac2 = _dev->uac2; struct snd_card *card; struct snd_pcm *pcm; - struct audio_dev *audio_dev; struct f_uac2_opts *opts; int err; int p_chmask, c_chmask; - audio_dev = uac2_to_agdev(uac2); opts = container_of(audio_dev->func.fi, struct f_uac2_opts, func_inst); p_chmask = opts->p_chmask; c_chmask = opts->c_chmask; /* Choose any slot, with no id */ - err = snd_card_new(>dev, -1, NULL, THIS_MODULE, 0, ); + err = snd_card_new(_dev->gadget->dev, + -1, NULL, THIS_MODULE, 0, ); if (err < 0) return err; @@ -481,16 +469,15 @@ static int snd_uac2_probe(struct platform_device *pdev) strcpy(card->driver, "UAC2_Gadget"); strcpy(card->shortname, "UAC2_Gadget"); - sprintf(card->longname, "UAC2_Gadget %i", pdev->id); + sprintf(card->longname, "UAC2_Gadget %i", card->dev->id); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); err = snd_card_register(card); - if (!err) { - platform_set_drvdata(pdev, card); + + if (!err) return 0; - } snd_fail: snd_card_free(card); @@ -501,9 +488,9 @@ static int snd_uac2_probe(struct platform_device *pdev) return err; } -static int snd_uac2_remove(struct platform_device *pdev) +static int snd_uac2_remove(struct audio_dev *audio_dev) { - struct snd_card *card = platform_get_drvdata(pdev); + struct snd_card *card = audio_dev->uac2.card; if (card) return snd_card_free(card); @@ -511,45 +498,6 @@ static int snd_uac2_remove(struct platform_device *pdev) return 0; } -static void snd_uac2_release(struct device *dev) -{ - dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); -} - -static int alsa_uac2_init(struct audio_dev *agdev) -{ - struct snd_uac2_chip *uac2 = >uac2; - int err; - - uac2->pdrv.probe = snd_uac2_probe; - uac2->pdrv.remove = snd_uac2_remove; - uac2->pdrv.driver.name = uac2_name; - - uac2->pdev.id = 0; - uac2->pdev.name = uac2_name; - uac2->pdev.dev.release = snd_uac2_release; - - /* Register snd_uac2 driver */ - err = platform_driver_register(>pdrv); - if (err) -
[PATCH v5 2/4] usb: gadget: f_uac2: split out audio core
Abstract the peripheral side ALSA sound card code from the f_uac2 function into a component that can be called by various functions, so the various flavors can be split apart and selectively reused. Visible changes: - add uac_params structure to pass audio paramteres for g_audio_setup - make ALSA sound card's name configurable - add [in/out]_ep_maxpsize - allocate snd_uac_chip structure during g_audio_setup - add u_audio_[start/stop]_[capture/playback] functions Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/Kconfig| 4 + drivers/usb/gadget/function/Makefile | 1 + drivers/usb/gadget/function/f_uac2.c | 718 -- drivers/usb/gadget/function/u_audio.c | 662 +++ drivers/usb/gadget/function/u_audio.h | 95 + drivers/usb/gadget/legacy/Kconfig | 1 + 6 files changed, 845 insertions(+), 636 deletions(-) create mode 100644 drivers/usb/gadget/function/u_audio.c create mode 100644 drivers/usb/gadget/function/u_audio.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index b3c879b..3b0ffd6 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -158,6 +158,9 @@ config USB_U_SERIAL config USB_U_ETHER tristate +config USB_U_AUDIO + tristate + config USB_F_SERIAL tristate @@ -381,6 +384,7 @@ config USB_CONFIGFS_F_UAC2 depends on SND select USB_LIBCOMPOSITE select SND_PCM + select USB_U_AUDIO select USB_F_UAC2 help This Audio function is compatible with USB Audio Class diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index cb8c225..b29f2ae 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -32,6 +32,7 @@ usb_f_mass_storage-y := f_mass_storage.o storage_common.o obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o usb_f_fs-y := f_fs.o obj-$(CONFIG_USB_F_FS) += usb_f_fs.o +obj-$(CONFIG_USB_U_AUDIO) += u_audio.o usb_f_uac1-y := f_uac1.o u_uac1.o obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o usb_f_uac2-y := f_uac2.o diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index f674bae..9082ce2 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -15,10 +15,7 @@ #include #include -#include -#include -#include - +#include "u_audio.h" #include "u_uac2.h" /* @@ -50,455 +47,23 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -struct uac2_req { - struct uac2_rtd_params *pp; /* parent param */ - struct usb_request *req; +struct f_uac2 { + struct g_audio g_audio; + u8 ac_intf, as_in_intf, as_out_intf; + u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ }; -struct uac2_rtd_params { - struct snd_uac2_chip *uac2; /* parent chip */ - bool ep_enabled; /* if the ep is enabled */ - /* Size of the ring buffer */ - size_t dma_bytes; - unsigned char *dma_area; - - struct snd_pcm_substream *ss; - - /* Ring buffer */ - ssize_t hw_ptr; - - void *rbuf; - - size_t period_size; - - unsigned max_psize; - struct uac2_req *ureq; - - spinlock_t lock; -}; - -struct snd_uac2_chip { - struct uac2_rtd_params p_prm; - struct uac2_rtd_params c_prm; - - struct snd_card *card; - struct snd_pcm *pcm; - - /* timekeeping for the playback endpoint */ - unsigned int p_interval; - unsigned int p_residue; - - /* pre-calculated values for playback iso completion */ - unsigned int p_pktsize; - unsigned int p_pktsize_residue; - unsigned int p_framesize; -}; - -#define BUFF_SIZE_MAX (PAGE_SIZE * 16) -#define PRD_SIZE_MAX PAGE_SIZE -#define MIN_PERIODS4 - -static struct snd_pcm_hardware uac2_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER -| SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID -| SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, - .rates = SNDRV_PCM_RATE_CONTINUOUS, - .periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX, - .buffer_bytes_max = BUFF_SIZE_MAX, - .period_bytes_max = PRD_SIZE_MAX, - .periods_min = MIN_PERIODS, -}; - -struct audio_dev { - u8 ac_intf, ac_alt; - u8 as_out_intf, as_out_alt; - u8 as_in_intf, as_in_alt; - - struct usb_ep *in_ep, *out_ep; - struct usb_function func; - struct usb_gadget *gadget; - - /* The ALSA Sound Card it represents on the USB-Client side */ - struct snd_uac2_chip uac2; -}; - -static inline -struct audio_dev *func_to_agdev(struct usb_function *f) -{ - return container_of(f, struct audio_dev, func); -} - -static inline -struc
[PATCH v5 4/4] usb: gadget: add f_uac1 variant based on a new u_audio api
This patch adds a new function 'f_uac1' (f_uac1 with virtual "ALSA card") that uses recently created u_audio API. Comparing to legacy f_uac1 function implementation it doesn't require any real Audio codec to be present on the device. In f_uac1 audio streams are simply sinked to and sourced from a virtual ALSA sound card created using u_audio API. Legacy f_uac1 approach is to write audio samples directly to existing ALSA sound card f_uac1 approach is more generic/flexible one - create an ALSA sound card that represents USB Audio function and allows to be used by userspace application that may choose to do whatever it wants with the data received from the USB Host and choose to provide whatever it wants as audio data to the USB Host. f_uac1 also has capture support (gadget->host) thanks to easy implementation via u_audio. By default, capture interface has 48000kHz/2ch configuration, same as playback channel has. f_uac1 descriptors naming convention uses f_uac2 driver naming convention that makes it more common and meaningful. Comparing to f_uac1_legacy, the f_uac1 doesn't have volume/mute functionality. This is because the f_uac1 volume/mute feature unit was dummy implementation since that driver creation (2009) and never had any real volume control or mute functionality, so there is no any difference here. Since f_uac1 functionality, exposed interface to userspace (virtual ALSA card), input parameters are so different comparing to f_uac1_legacy, that there is no any reason to keep them in the same file/module, and separate function was created. g_audio can be built using one of existing UAC functions (f_uac1, f_uac1_legacy or f_uac2) Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- Documentation/ABI/testing/configfs-usb-gadget-uac1 | 14 + Documentation/usb/gadget-testing.txt | 44 ++ drivers/usb/gadget/Kconfig | 25 +- drivers/usb/gadget/function/Makefile | 2 + drivers/usb/gadget/function/f_uac1.c | 802 + drivers/usb/gadget/function/u_uac1.h | 41 ++ drivers/usb/gadget/legacy/Kconfig | 18 +- drivers/usb/gadget/legacy/audio.c | 69 +- 8 files changed, 1000 insertions(+), 15 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac1 create mode 100644 drivers/usb/gadget/function/f_uac1.c create mode 100644 drivers/usb/gadget/function/u_uac1.h diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac1 b/Documentation/ABI/testing/configfs-usb-gadget-uac1 new file mode 100644 index 000..abfe447 --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-uac1 @@ -0,0 +1,14 @@ +What: /config/usb-gadget/gadget/functions/uac1.name +Date: June 2017 +KernelVersion: 4.14 +Description: + The attributes: + + c_chmask - capture channel mask + c_srate - capture sampling rate + c_ssize - capture sample size (bytes) + p_chmask - playback channel mask + p_srate - playback sampling rate + p_ssize - playback sample size (bytes) + req_number - the number of pre-allocated request + for both capture and playback diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index ce51d6e..fbc397d 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -20,6 +20,7 @@ provided by gadgets. 17. UAC2 function 18. UVC function 19. PRINTER function +20. UAC1 function (new API) 1. ACM function @@ -773,3 +774,46 @@ host: More advanced testing can be done with the prn_example described in Documentation/usb/gadget-printer.txt. + + +20. UAC1 function (virtual ALSA card, using u_audio API) += + +The function is provided by usb_f_uac1.ko module. +It will create a virtual ALSA card and the audio streams are simply +sinked to and sourced from it. + +Function-specific configfs interface + + +The function name to use when creating the function directory is "uac1". +The uac1 function provides these attributes in its function directory: + + c_chmask - capture channel mask + c_srate - capture sampling rate + c_ssize - capture sample size (bytes) + p_chmask - playback channel mask + p_srate - playback sampling rate + p_ssize - playback sample size (bytes) + req_number - the number of pre-allocated request for both capture +and playback + +The attributes have sane default values. + +Testing the UAC1 function +- + +device: run the gadget +host: aplay -l # should list our USB Audio Gadget + +This function does not require real hardware support, it just +sends a stream of audio data to/from the host. In order to +actually hear something at the d
[PATCH v5 3/4] usb: gadget: function: make current f_uac1 implementation legacy
Before introducing new f_uac1 function (with virtual ALSA card) make current implementation legacy. This includes renaming of existing files, some variables, config options and documentation Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- ...gadget-uac1 => configfs-usb-gadget-uac1_legacy} | 2 +- Documentation/usb/gadget-testing.txt | 9 +++-- drivers/usb/gadget/Kconfig | 8 ++-- drivers/usb/gadget/function/Makefile | 4 +- .../gadget/function/{f_uac1.c => f_uac1_legacy.c} | 45 +++--- .../gadget/function/{u_uac1.c => u_uac1_legacy.c} | 7 ++-- .../gadget/function/{u_uac1.h => u_uac1_legacy.h} | 8 ++-- drivers/usb/gadget/legacy/Kconfig | 6 +-- drivers/usb/gadget/legacy/audio.c | 26 ++--- 9 files changed, 59 insertions(+), 56 deletions(-) rename Documentation/ABI/testing/{configfs-usb-gadget-uac1 => configfs-usb-gadget-uac1_legacy} (84%) rename drivers/usb/gadget/function/{f_uac1.c => f_uac1_legacy.c} (95%) rename drivers/usb/gadget/function/{u_uac1.c => u_uac1_legacy.c} (98%) rename drivers/usb/gadget/function/{u_uac1.h => u_uac1_legacy.h} (94%) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac1 b/Documentation/ABI/testing/configfs-usb-gadget-uac1_legacy similarity index 84% rename from Documentation/ABI/testing/configfs-usb-gadget-uac1 rename to Documentation/ABI/testing/configfs-usb-gadget-uac1_legacy index 8ba9a12..b2eaefd 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uac1 +++ b/Documentation/ABI/testing/configfs-usb-gadget-uac1_legacy @@ -1,4 +1,4 @@ -What: /config/usb-gadget/gadget/functions/uac1.name +What: /config/usb-gadget/gadget/functions/uac1_legacy.name Date: Sep 2014 KernelVersion: 3.18 Description: diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index fb0cc4d..ce51d6e 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -16,7 +16,7 @@ provided by gadgets. 13. RNDIS function 14. SERIAL function 15. SOURCESINK function -16. UAC1 function +16. UAC1 function (legacy implementation) 17. UAC2 function 18. UVC function 19. PRINTER function @@ -589,15 +589,16 @@ device: run the gadget host: test-usb (tools/usb/testusb.c) -16. UAC1 function +16. UAC1 function (legacy implementation) = -The function is provided by usb_f_uac1.ko module. +The function is provided by usb_f_uac1_legacy.ko module. Function-specific configfs interface -The function name to use when creating the function directory is "uac1". +The function name to use when creating the function directory +is "uac1_legacy". The uac1 function provides these attributes in its function directory: audio_buf_size - audio buffer size diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3b0ffd6..01c2e2b 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -191,7 +191,7 @@ config USB_F_MASS_STORAGE config USB_F_FS tristate -config USB_F_UAC1 +config USB_F_UAC1_LEGACY tristate config USB_F_UAC2 @@ -365,13 +365,13 @@ config USB_CONFIGFS_F_FS implemented in kernel space (for instance Ethernet, serial or mass storage) and other are implemented in user space. -config USB_CONFIGFS_F_UAC1 - bool "Audio Class 1.0" +config USB_CONFIGFS_F_UAC1_LEGACY + bool "Audio Class 1.0 (legacy implementation)" depends on USB_CONFIGFS depends on SND select USB_LIBCOMPOSITE select SND_PCM - select USB_F_UAC1 + select USB_F_UAC1_LEGACY help This Audio function implements 1 AudioControl interface, 1 AudioStreaming Interface each for USB-OUT and USB-IN. diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index b29f2ae..50ee517 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -33,8 +33,8 @@ obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o usb_f_fs-y := f_fs.o obj-$(CONFIG_USB_F_FS) += usb_f_fs.o obj-$(CONFIG_USB_U_AUDIO) += u_audio.o -usb_f_uac1-y := f_uac1.o u_uac1.o -obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o +usb_f_uac1_legacy-y:= f_uac1_legacy.o u_uac1_legacy.o +obj-$(CONFIG_USB_F_UAC1_LEGACY)+= usb_f_uac1_legacy.o usb_f_uac2-y := f_uac2.o obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o usb_f_uvc-y:= f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.o diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1_legacy.c similarity index 95% rename from drivers/usb/gadget/function/f_uac1.c rename to drivers/usb/gadget/function/
[PATCH] usb: gadget: function: f_uac1: implement get_alt()
After commit 7e4da3fcf7c9 ("usb: gadget: composite: Test get_alt() presence instead of set_alt()") f_uac1 function became broken because it doesn't have get_alt() callback implementation and composite framework never set altsetting 1 for audiostreaming interface. On host site it looks like: [424339.017711] 21:1:1: usb_set_interface failed (-32) Since host can't set altsetting 1, it can't start playing audio. In order to fix it implemented get_alt along with minor improvements (error conditions checking) similar to what existing f_uac2 has. Cc: Krzysztof Opasiak <k.opas...@samsung.com> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/function/f_uac1.c | 40 +++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index f2ac0cb..5dfc94b 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -277,6 +277,9 @@ static void f_audio_buffer_free(struct f_audio_buf *audio_buf) struct f_audio { struct gaudio card; + u8 ac_intf, ac_alt; + u8 as_intf, as_alt; + /* endpoints handle full and/or high speeds */ struct usb_ep *out_ep; @@ -586,7 +589,20 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) req_count = opts->req_count; audio_buf_size = opts->audio_buf_size; - if (intf == 1) { + /* No i/f has more than 2 alt settings */ + if (alt > 1) { + ERROR(cdev, "%s:%d Error!\n", __func__, __LINE__); + return -EINVAL; + } + + if (intf == audio->ac_intf) { + /* Control I/f has only 1 AltSetting - 0 */ + if (alt) { + ERROR(cdev, "%s:%d Error!\n", __func__, __LINE__); + return -EINVAL; + } + return 0; + } else if (intf == audio->as_intf) { if (alt == 1) { err = config_ep_by_speed(cdev->gadget, f, out_ep); if (err) @@ -631,11 +647,28 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) schedule_work(>playback_work); } } + audio->as_alt = alt; } return err; } +static int f_audio_get_alt(struct usb_function *f, unsigned intf) +{ + struct f_audio *audio = func_to_audio(f); + struct usb_composite_dev *cdev = f->config->cdev; + + if (intf == audio->ac_intf) + return audio->ac_alt; + else if (intf == audio->as_intf) + return audio->as_alt; + else + ERROR(cdev, "%s:%d Invalid Interface %d!\n", + __func__, __LINE__, intf); + + return -EINVAL; +} + static void f_audio_disable(struct usb_function *f) { return; @@ -702,12 +735,16 @@ static void f_audio_build_desc(struct f_audio *audio) if (status < 0) goto fail; ac_interface_desc.bInterfaceNumber = status; + audio->ac_intf = status; + audio->ac_alt = 0; status = usb_interface_id(c, f); if (status < 0) goto fail; as_interface_alt_0_desc.bInterfaceNumber = status; as_interface_alt_1_desc.bInterfaceNumber = status; + audio->as_intf = status; + audio->as_alt = 0; status = -ENODEV; @@ -966,6 +1003,7 @@ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi) audio->card.func.bind = f_audio_bind; audio->card.func.unbind = f_audio_unbind; audio->card.func.set_alt = f_audio_set_alt; + audio->card.func.get_alt = f_audio_get_alt; audio->card.func.setup = f_audio_setup; audio->card.func.disable = f_audio_disable; audio->card.func.free_func = f_audio_free; -- 1.9.1 -- 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 v4 0/3] USB Audio Gadget refactoring
On Tue, Jun 6, 2017 at 12:41 PM, Felipe Balbiwrote: > > Hi, > > Greg KH writes: >>> > I'm OK with dropping legacy f_uac1 implementation. >>> > >>> > Another idea I was thinking about is to implement simple in-kernel >>> > driver which will do the same as existing alsaloop tool userspace >>> > tool does (so legacy users will need to load two kernel modules >>> > and get same functionality). But this seems to be a wrong way, >>> > since It known that Linux kernel community doesn't like to take drivers >>> > with same functionality as existing userspace tools already have. >>> > >>> > So bottom line: since I'm not a legacy f_uac1 user, there is no >>> > difference for me how to handle it - remove legacy f_uac1 completely, >>> > rename it to f_uac1_legacy or add separate f_uac1_acard function. >>> > >>> > So if dropping of legacy f_uac1 implementation is OK for you, >>> > I can do it quickly in next patchset. >>> >>> Personally, I don't want duplicated functionality and I think the >>> virtual sound card approach is much better. Then again, removing >>> functionality we already support is kind of odd. >>> >>> Greg, Alan, what do you guys think? Do we keep a duplicated function >>> around or do we just tell people to rely on alsaloop? Personally, I >>> think we're better off with the flexibility of the virtual sound card, >>> what's your take? >> >> If the in-kernel driver will do more things, and we don't break the >> existing setups using alsaloop, then I don't see the problem, except >> that we now have to maintain two things :) >> >> If you don't mind the maintenance, fine with me... > > Okay, I don't think many will continue to use f_uac1.c. Ruslan, can you > update your series so that current f_uac1.c gets renamed to > f_uac1_legacy.c and you introduce a *new* f_uac1.c instead? Yes sure, I'll post an updated patch series soon Best regards, Ruslan -- 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 v2 resend] omap: usb: host: remove deprecated flags and structures
From: Ruslan Bilovol <ruslan.bilo...@ti.com> These flags and structures are deprecated and there is no anymore users of them, so it's safe to remove them. Signed-off-by: Ruslan Bilovol <ruslan.bilo...@ti.com> --- Although this patch was acked-by Felipe Balbi and Roger Quadros back in 2013, it was never picked up by maintainers. Still applies to v4.12-rc3 and saves few bytes of memory include/linux/platform_data/usb-omap.h | 20 1 file changed, 20 deletions(-) diff --git a/include/linux/platform_data/usb-omap.h b/include/linux/platform_data/usb-omap.h index fa579b4..4c7acbe 100644 --- a/include/linux/platform_data/usb-omap.h +++ b/include/linux/platform_data/usb-omap.h @@ -38,34 +38,14 @@ enum usbhs_omap_port_mode { OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM }; -struct usbtll_omap_platform_data { - enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; -}; - -struct ehci_hcd_omap_platform_data { - enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; - int reset_gpio_port[OMAP3_HS_USB_PORTS]; - struct regulator*regulator[OMAP3_HS_USB_PORTS]; - unsignedphy_reset:1; -}; - -struct ohci_hcd_omap_platform_data { - enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; - unsignedes2_compatibility:1; -}; - struct usbhs_omap_platform_data { int nports; enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; int reset_gpio_port[OMAP3_HS_USB_PORTS]; struct regulator*regulator[OMAP3_HS_USB_PORTS]; - struct ehci_hcd_omap_platform_data *ehci_data; - struct ohci_hcd_omap_platform_data *ohci_data; - /* OMAP3 <= ES2.1 have a single ulpi bypass control bit */ unsigned single_ulpi_bypass:1; - unsigned es2_compatibility:1; unsigned phy_reset:1; }; -- 1.9.1 -- 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 v4 0/3] USB Audio Gadget refactoring
Hi, On Fri, Jun 2, 2017 at 12:42 PM, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Ruslan Bilovol <ruslan.bilo...@gmail.com> writes: >> I came to this patch series when wanted to do two things: >> - use UAC1 as virtual ALSA sound card on gadget side, >>just like UAC2 is used so it's possible to do rate >>resampling >> - have both playback/capture support in UAC1 >> >> Since I wanted to have same behavior for both UAC1/UAC2, >> obviously I've got an utility part (u_audio.c) for >> virtual ALSA sound card handling like we have >> for ethernet(u_ether) or serial(u_serial) functions. >> Function-specific parts (f_uac1/f_uac2) became almost >> as storage for class-specific USB descriptors, some >> boilerplate for configfs, binding and few USB >> config request handling. >> >> Originally in RFC [1] I've posted before, there was >> major change to f_uac1 after that it couldn't do >> direct play to existing ALSA sound card anymore, >> representing audio on gadget side as virtual >> ALSA sound card where audio streams are simply >> sinked to and sourced from it, so it may break >> current usecase for some people (and that's why >> it was RFC). >> >> During RFC discussion, it was agreed to not touch >> existing f_uac1 implementation and create new one >> instead. This patchset (v4) introduced new function >> named f_uac1_acard and doesn't touch current f_uac1 >> implementation, so people still can use old behavior > > Do you have a pointer to the original RFC discussion where this was > discussed? If we really *must* keep the old implementation, I would > rather rename that to f_uac1_legacy. Still, I find it unlikely that > anybody will care about the old implementation. It is on LKML (which is down for me) [1] or alternative archive [2] > >> Now, it's possible to use existing user-space >> applications for audio routing between Audio Gadget >> and real sound card. I personally use alsaloop tool >> from alsautils and have ability to create PCM >> loopback between two different ALSA cards using >> rate resampling, which was not possible with previous >> "direct play to ALSA card" approach in f_uac1. > > this is really good result and will actually make it a lot easier for > testing things out. > >> While here, also dropped redundant platform >> driver/device creation in f_uac2 driver (as well as >> didn't add "never implemented" volume/mute functionality >> in f_uac1 to f_uac1_acard) that made this work even >> easier to do. >> >> This series is tested with both legacy g_audio.ko and >> modern configfs approaches under Ubuntu 14.04 (UAC1 and >> UAC2) and under Windows7 x64 (UAC1 only) having >> perfect results in all cases. >> >> Comments, testing are welcome. >> >> v4 changes: >> - renamed f_uac1_newapi to f_uac1_acard that is >>more meaningful > > I really don't get why you wanna keep both f_uac1 and f_uac1_acard. Why > do we need to maintain the old uac1 implementation? Why two separate > files? In first RFC ([1],[2]) I did exactly what you wrote here (removed old uac1 implementation and replaced it by new one) but got feedback that it will break things for existing f_uac1 legacy users and it's better to have separate implementation. I'm OK with dropping legacy f_uac1 implementation. Another idea I was thinking about is to implement simple in-kernel driver which will do the same as existing alsaloop tool userspace tool does (so legacy users will need to load two kernel modules and get same functionality). But this seems to be a wrong way, since It known that Linux kernel community doesn't like to take drivers with same functionality as existing userspace tools already have. So bottom line: since I'm not a legacy f_uac1 user, there is no difference for me how to handle it - remove legacy f_uac1 completely, rename it to f_uac1_legacy or add separate f_uac1_acard function. So if dropping of legacy f_uac1 implementation is OK for you, I can do it quickly in next patchset. [1] https://lkml.org/lkml/2016/5/23/649 [2] https://marc.info/?t=14640475881=1=4 Regards, Ruslan -- 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 v4 2/3] usb: gadget: f_uac2: split out audio core
Hi Felipe, On Fri, Jun 2, 2017 at 12:34 PM, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Ruslan Bilovol <ruslan.bilo...@gmail.com> writes: >> Abstract the peripheral side ALSA sound card code from >> the f_uac2 function into a component that can be called >> by various functions, so the various flavors can be split >> apart and selectively reused. >> >> Visible changes: >> - add uac_params structure to pass audio paramteres for >>g_audio_setup >> - make ALSA sound card's name configurable >> - add [in/out]_ep_maxpsize >> - allocate snd_uac_chip structure during g_audio_setup >> - add u_audio_[start/stop]_[capture/playback] functions >> >> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> > > this doesn't apply on testing/next, care to rebase? > sure, I'll rebase it and address comments from Jassi Regards, Ruslan -- 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 v4 3/3] usb: gadget: add f_uac1 variant based on a new u_audio api
On Fri, May 26, 2017 at 6:52 PM, Julian Scheel <jul...@jusst.de> wrote: > On 18.05.2017 00:37, Ruslan Bilovol wrote: >> >> This patch adds a new function 'f_uac1_acard' >> (f_uac1 with virtual "ALSA card") that >> uses recently created u_audio API. Comparing >> to legacy f_uac1 function implementation it >> doesn't require any real Audio codec to be >> present on the device. In f_uac1_acard audio >> streams are simply sinked to and sourced >> from a virtual ALSA sound card created >> using u_audio API. >> >> Legacy f_uac1 approach is to write audio >> samples directly to existing ALSA sound >> card >> >> f_uac1_acard approach is more generic/flexible >> one - create an ALSA sound card that >> represents USB Audio function and allows to >> be used by userspace application that >> may choose to do whatever it wants with the >> data received from the USB Host and choose >> to provide whatever it wants as audio data >> to the USB Host. >> >> f_uac1_acard also has capture support (gadget->host) >> thanks to easy implementation via u_audio. >> By default, capture interface has 48000kHz/2ch >> configuration, same as playback channel has. >> >> f_uac1_acard descriptors naming convention >> uses f_uac2 driver naming convention that >> makes it more common and meaningful. >> >> Comparing to f_uac1, the f_uac1_acard doesn't >> have volume/mute functionality. This is because >> the f_uac1 volume/mute feature unit was dummy >> implementation since that driver creation (2009) >> and never had any real volume control or mute >> functionality, so there is no any difference >> here. >> >> Since f_uac1_acard functionality, exposed >> interface to userspace (virtual ALSA card), >> input parameters are so different comparing >> to legace f_uac1, that there is no any >> reason to keep them in the same file/module, >> and separate function was created. >> >> g_audio can be built using one of existing >> UAC functions (f_uac1, f_uac1_acard or f_uac2) >> >> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> >> --- >> .../ABI/testing/configfs-usb-gadget-uac1_acard | 14 + >> Documentation/usb/gadget-testing.txt | 45 ++ >> drivers/usb/gadget/Kconfig | 21 + >> drivers/usb/gadget/function/Makefile | 2 + >> drivers/usb/gadget/function/f_uac1_acard.c | 803 >> + >> drivers/usb/gadget/function/u_uac1_acard.h | 41 ++ >> drivers/usb/gadget/legacy/Kconfig | 15 +- >> drivers/usb/gadget/legacy/audio.c | 53 ++ >> 8 files changed, 992 insertions(+), 2 deletions(-) >> create mode 100644 >> Documentation/ABI/testing/configfs-usb-gadget-uac1_acard >> create mode 100644 drivers/usb/gadget/function/f_uac1_acard.c >> create mode 100644 drivers/usb/gadget/function/u_uac1_acard.h >> > > Tested on iMX7D using chipidea usb gadget controller. Tested Windows 10 and > Linux 4.11 as host. Both work fine. > > Tested-by: Julian Scheel <jul...@jusst.de> Thanks for testing it. I'll wait for additional reviews/comments next few days and than will send new patchset with addressed comments. Also current patchset have minor conflict when applied on top of Felipe's testing/next branch which is moved to 4.12-rc1. I've resolved conflict but did only build test so far. Anyway I uploaded rebased patches to github [1] if anybody wants to try them. [1] https://github.com/rbilovol/kernel/commits/usbaudio-v4.12-balbi-testing-next Best regards, Ruslan -- 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 v4 2/3] usb: gadget: f_uac2: split out audio core
On Mon, May 22, 2017 at 6:58 PM, Jassi Brar <jassisinghb...@gmail.com> wrote: > On Thu, May 18, 2017 at 4:07 AM, Ruslan Bilovol > <ruslan.bilo...@gmail.com> wrote: >> Abstract the peripheral side ALSA sound card code from >> the f_uac2 function into a component that can be called >> by various functions, so the various flavors can be split >> apart and selectively reused. >> >> Visible changes: >> - add uac_params structure to pass audio paramteres for >>g_audio_setup >> - make ALSA sound card's name configurable >> - add [in/out]_ep_maxpsize >> - allocate snd_uac_chip structure during g_audio_setup >> - add u_audio_[start/stop]_[capture/playback] functions >> >> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> >> --- >> drivers/usb/gadget/Kconfig| 4 + >> drivers/usb/gadget/function/Makefile | 1 + >> drivers/usb/gadget/function/f_uac2.c | 721 >> -- >> drivers/usb/gadget/function/u_audio.c | 661 +++ >> drivers/usb/gadget/function/u_audio.h | 95 + >> drivers/usb/gadget/legacy/Kconfig | 1 + >> 6 files changed, 846 insertions(+), 637 deletions(-) >> create mode 100644 drivers/usb/gadget/function/u_audio.c >> create mode 100644 drivers/usb/gadget/function/u_audio.h >> >> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig >> index c164d6b..2ba0ace 100644 >> --- a/drivers/usb/gadget/Kconfig >> +++ b/drivers/usb/gadget/Kconfig >> @@ -158,6 +158,9 @@ config USB_U_SERIAL >> config USB_U_ETHER >> tristate >> >> +config USB_U_AUDIO >> + tristate >> + >> config USB_F_SERIAL >> tristate >> >> @@ -381,6 +384,7 @@ config USB_CONFIGFS_F_UAC2 >> depends on SND >> select USB_LIBCOMPOSITE >> select SND_PCM >> + select USB_U_AUDIO >> select USB_F_UAC2 >> help >> This Audio function is compatible with USB Audio Class >> diff --git a/drivers/usb/gadget/function/Makefile >> b/drivers/usb/gadget/function/Makefile >> index cb8c225..b29f2ae 100644 >> --- a/drivers/usb/gadget/function/Makefile >> +++ b/drivers/usb/gadget/function/Makefile >> @@ -32,6 +32,7 @@ usb_f_mass_storage-y := f_mass_storage.o >> storage_common.o >> obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o >> usb_f_fs-y := f_fs.o >> obj-$(CONFIG_USB_F_FS) += usb_f_fs.o >> +obj-$(CONFIG_USB_U_AUDIO) += u_audio.o >> usb_f_uac1-y := f_uac1.o u_uac1.o >> obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o >> usb_f_uac2-y := f_uac2.o >> diff --git a/drivers/usb/gadget/function/f_uac2.c >> b/drivers/usb/gadget/function/f_uac2.c >> index d4565b5..059a14a 100644 >> --- a/drivers/usb/gadget/function/f_uac2.c >> +++ b/drivers/usb/gadget/function/f_uac2.c >> @@ -15,10 +15,7 @@ >> #include >> #include >> >> -#include >> -#include >> -#include >> - >> +#include "u_audio.h" >> #include "u_uac2.h" >> >> /* >> @@ -50,455 +47,23 @@ >> #define UNFLW_CTRL 8 >> #define OVFLW_CTRL 10 >> >> -struct uac2_req { >> - struct uac2_rtd_params *pp; /* parent param */ >> - struct usb_request *req; >> -}; >> - >> -struct uac2_rtd_params { >> - struct snd_uac2_chip *uac2; /* parent chip */ >> - bool ep_enabled; /* if the ep is enabled */ >> - /* Size of the ring buffer */ >> - size_t dma_bytes; >> - unsigned char *dma_area; >> - >> - struct snd_pcm_substream *ss; >> - >> - /* Ring buffer */ >> - ssize_t hw_ptr; >> - >> - void *rbuf; >> - >> - size_t period_size; >> - >> - unsigned max_psize; >> - struct uac2_req *ureq; >> - >> - spinlock_t lock; >> -}; >> - >> -struct snd_uac2_chip { >> - struct uac2_rtd_params p_prm; >> - struct uac2_rtd_params c_prm; >> - >> - struct snd_card *card; >> - struct snd_pcm *pcm; >> - >> - /* timekeeping for the playback endpoint */ >> - unsigned int p_interval; >> - unsigned int p_residue; >> - >> - /* pre-calculated values for playback iso completion */ >> - unsigned int p_pktsize; >> - unsigned int p_pktsize_residue; >&
[PATCH v4 0/3] USB Audio Gadget refactoring
I came to this patch series when wanted to do two things: - use UAC1 as virtual ALSA sound card on gadget side, just like UAC2 is used so it's possible to do rate resampling - have both playback/capture support in UAC1 Since I wanted to have same behavior for both UAC1/UAC2, obviously I've got an utility part (u_audio.c) for virtual ALSA sound card handling like we have for ethernet(u_ether) or serial(u_serial) functions. Function-specific parts (f_uac1/f_uac2) became almost as storage for class-specific USB descriptors, some boilerplate for configfs, binding and few USB config request handling. Originally in RFC [1] I've posted before, there was major change to f_uac1 after that it couldn't do direct play to existing ALSA sound card anymore, representing audio on gadget side as virtual ALSA sound card where audio streams are simply sinked to and sourced from it, so it may break current usecase for some people (and that's why it was RFC). During RFC discussion, it was agreed to not touch existing f_uac1 implementation and create new one instead. This patchset (v4) introduced new function named f_uac1_acard and doesn't touch current f_uac1 implementation, so people still can use old behavior Now, it's possible to use existing user-space applications for audio routing between Audio Gadget and real sound card. I personally use alsaloop tool from alsautils and have ability to create PCM loopback between two different ALSA cards using rate resampling, which was not possible with previous "direct play to ALSA card" approach in f_uac1. While here, also dropped redundant platform driver/device creation in f_uac2 driver (as well as didn't add "never implemented" volume/mute functionality in f_uac1 to f_uac1_acard) that made this work even easier to do. This series is tested with both legacy g_audio.ko and modern configfs approaches under Ubuntu 14.04 (UAC1 and UAC2) and under Windows7 x64 (UAC1 only) having perfect results in all cases. Comments, testing are welcome. v4 changes: - renamed f_uac1_newapi to f_uac1_acard that is more meaningful - rebased on top of balbi/next v3 changes: - renamed u_audio exported symbols so they don't conflict with old f_uac1 if both are built-in. v2 changes: - do not touch f_uac1, instead created f_uac1_newapi - added documentation for f_uac1_newapi - rebased on top of v4.8-rc1 [1] https://lkml.org/lkml/2016/5/23/649 Ruslan Bilovol (3): usb: gadget: f_uac2: remove platform driver/device creation usb: gadget: f_uac2: split out audio core usb: gadget: add f_uac1 variant based on a new u_audio api .../ABI/testing/configfs-usb-gadget-uac1_acard | 14 + Documentation/usb/gadget-testing.txt | 45 ++ drivers/usb/gadget/Kconfig | 25 + drivers/usb/gadget/function/Makefile | 3 + drivers/usb/gadget/function/f_uac1_acard.c | 803 + drivers/usb/gadget/function/f_uac2.c | 798 +++- drivers/usb/gadget/function/u_audio.c | 661 + drivers/usb/gadget/function/u_audio.h | 95 +++ drivers/usb/gadget/function/u_uac1_acard.h | 41 ++ drivers/usb/gadget/legacy/Kconfig | 14 +- drivers/usb/gadget/legacy/audio.c | 53 ++ 11 files changed, 1850 insertions(+), 702 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac1_acard create mode 100644 drivers/usb/gadget/function/f_uac1_acard.c create mode 100644 drivers/usb/gadget/function/u_audio.c create mode 100644 drivers/usb/gadget/function/u_audio.h create mode 100644 drivers/usb/gadget/function/u_uac1_acard.h -- 1.9.1 -- 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 v4 2/3] usb: gadget: f_uac2: split out audio core
Abstract the peripheral side ALSA sound card code from the f_uac2 function into a component that can be called by various functions, so the various flavors can be split apart and selectively reused. Visible changes: - add uac_params structure to pass audio paramteres for g_audio_setup - make ALSA sound card's name configurable - add [in/out]_ep_maxpsize - allocate snd_uac_chip structure during g_audio_setup - add u_audio_[start/stop]_[capture/playback] functions Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/Kconfig| 4 + drivers/usb/gadget/function/Makefile | 1 + drivers/usb/gadget/function/f_uac2.c | 721 -- drivers/usb/gadget/function/u_audio.c | 661 +++ drivers/usb/gadget/function/u_audio.h | 95 + drivers/usb/gadget/legacy/Kconfig | 1 + 6 files changed, 846 insertions(+), 637 deletions(-) create mode 100644 drivers/usb/gadget/function/u_audio.c create mode 100644 drivers/usb/gadget/function/u_audio.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index c164d6b..2ba0ace 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -158,6 +158,9 @@ config USB_U_SERIAL config USB_U_ETHER tristate +config USB_U_AUDIO + tristate + config USB_F_SERIAL tristate @@ -381,6 +384,7 @@ config USB_CONFIGFS_F_UAC2 depends on SND select USB_LIBCOMPOSITE select SND_PCM + select USB_U_AUDIO select USB_F_UAC2 help This Audio function is compatible with USB Audio Class diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index cb8c225..b29f2ae 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -32,6 +32,7 @@ usb_f_mass_storage-y := f_mass_storage.o storage_common.o obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o usb_f_fs-y := f_fs.o obj-$(CONFIG_USB_F_FS) += usb_f_fs.o +obj-$(CONFIG_USB_U_AUDIO) += u_audio.o usb_f_uac1-y := f_uac1.o u_uac1.o obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o usb_f_uac2-y := f_uac2.o diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index d4565b5..059a14a 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -15,10 +15,7 @@ #include #include -#include -#include -#include - +#include "u_audio.h" #include "u_uac2.h" /* @@ -50,455 +47,23 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -struct uac2_req { - struct uac2_rtd_params *pp; /* parent param */ - struct usb_request *req; -}; - -struct uac2_rtd_params { - struct snd_uac2_chip *uac2; /* parent chip */ - bool ep_enabled; /* if the ep is enabled */ - /* Size of the ring buffer */ - size_t dma_bytes; - unsigned char *dma_area; - - struct snd_pcm_substream *ss; - - /* Ring buffer */ - ssize_t hw_ptr; - - void *rbuf; - - size_t period_size; - - unsigned max_psize; - struct uac2_req *ureq; - - spinlock_t lock; -}; - -struct snd_uac2_chip { - struct uac2_rtd_params p_prm; - struct uac2_rtd_params c_prm; - - struct snd_card *card; - struct snd_pcm *pcm; - - /* timekeeping for the playback endpoint */ - unsigned int p_interval; - unsigned int p_residue; - - /* pre-calculated values for playback iso completion */ - unsigned int p_pktsize; - unsigned int p_pktsize_residue; - unsigned int p_framesize; +struct f_uac2 { + struct g_audio g_audio; + u8 ac_intf, as_in_intf, as_out_intf; + u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ }; -#define BUFF_SIZE_MAX (PAGE_SIZE * 16) -#define PRD_SIZE_MAX PAGE_SIZE -#define MIN_PERIODS4 - -static struct snd_pcm_hardware uac2_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER -| SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID -| SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, - .rates = SNDRV_PCM_RATE_CONTINUOUS, - .periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX, - .buffer_bytes_max = BUFF_SIZE_MAX, - .period_bytes_max = PRD_SIZE_MAX, - .periods_min = MIN_PERIODS, -}; - -struct audio_dev { - u8 ac_intf, ac_alt; - u8 as_out_intf, as_out_alt; - u8 as_in_intf, as_in_alt; - - struct usb_ep *in_ep, *out_ep; - struct usb_function func; - struct usb_gadget *gadget; - - /* The ALSA Sound Card it represents on the USB-Client side */ - struct snd_uac2_chip uac2; -}; - -static inline -struct audio_dev *func_to_agdev(struct usb_function *f) +static inline struct f_uac2 *func_to_uac2(struct usb_function *f) { - ret
[PATCH v4 3/3] usb: gadget: add f_uac1 variant based on a new u_audio api
This patch adds a new function 'f_uac1_acard' (f_uac1 with virtual "ALSA card") that uses recently created u_audio API. Comparing to legacy f_uac1 function implementation it doesn't require any real Audio codec to be present on the device. In f_uac1_acard audio streams are simply sinked to and sourced from a virtual ALSA sound card created using u_audio API. Legacy f_uac1 approach is to write audio samples directly to existing ALSA sound card f_uac1_acard approach is more generic/flexible one - create an ALSA sound card that represents USB Audio function and allows to be used by userspace application that may choose to do whatever it wants with the data received from the USB Host and choose to provide whatever it wants as audio data to the USB Host. f_uac1_acard also has capture support (gadget->host) thanks to easy implementation via u_audio. By default, capture interface has 48000kHz/2ch configuration, same as playback channel has. f_uac1_acard descriptors naming convention uses f_uac2 driver naming convention that makes it more common and meaningful. Comparing to f_uac1, the f_uac1_acard doesn't have volume/mute functionality. This is because the f_uac1 volume/mute feature unit was dummy implementation since that driver creation (2009) and never had any real volume control or mute functionality, so there is no any difference here. Since f_uac1_acard functionality, exposed interface to userspace (virtual ALSA card), input parameters are so different comparing to legace f_uac1, that there is no any reason to keep them in the same file/module, and separate function was created. g_audio can be built using one of existing UAC functions (f_uac1, f_uac1_acard or f_uac2) Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- .../ABI/testing/configfs-usb-gadget-uac1_acard | 14 + Documentation/usb/gadget-testing.txt | 45 ++ drivers/usb/gadget/Kconfig | 21 + drivers/usb/gadget/function/Makefile | 2 + drivers/usb/gadget/function/f_uac1_acard.c | 803 + drivers/usb/gadget/function/u_uac1_acard.h | 41 ++ drivers/usb/gadget/legacy/Kconfig | 15 +- drivers/usb/gadget/legacy/audio.c | 53 ++ 8 files changed, 992 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac1_acard create mode 100644 drivers/usb/gadget/function/f_uac1_acard.c create mode 100644 drivers/usb/gadget/function/u_uac1_acard.h diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac1_acard b/Documentation/ABI/testing/configfs-usb-gadget-uac1_acard new file mode 100644 index 000..2cffeaa --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-uac1_acard @@ -0,0 +1,14 @@ +What: /config/usb-gadget/gadget/functions/uac1_acard.name +Date: May 2017 +KernelVersion: 4.13 +Description: + The attributes: + + c_chmask - capture channel mask + c_srate - capture sampling rate + c_ssize - capture sample size (bytes) + p_chmask - playback channel mask + p_srate - playback sampling rate + p_ssize - playback sample size (bytes) + req_number - the number of pre-allocated request + for both capture and playback diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index fb0cc4d..ecff3ec 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -20,6 +20,7 @@ provided by gadgets. 17. UAC2 function 18. UVC function 19. PRINTER function +20. UAC1 function (new API) 1. ACM function @@ -772,3 +773,47 @@ host: More advanced testing can be done with the prn_example described in Documentation/usb/gadget-printer.txt. + + +20. UAC1 function (virtual ALSA card, using u_audio API) += + +The function is provided by usb_f_uac1_acard.ko module. +It will create a virtual ALSA card and the audio streams are simply +sinked to and sourced from it. + +Function-specific configfs interface + + +The function name to use when creating the function directory +is "uac1_acard". The uac1_acard function provides these attributes +in its function directory: + + c_chmask - capture channel mask + c_srate - capture sampling rate + c_ssize - capture sample size (bytes) + p_chmask - playback channel mask + p_srate - playback sampling rate + p_ssize - playback sample size (bytes) + req_number - the number of pre-allocated request for both capture +and playback + +The attributes have sane default values. + +Testing the UAC1 function +- + +device: run the gadget +host: aplay -l # should list our USB Audio Gadget + +This function does not require real hardware support, it just +sends a
[PATCH v4 1/3] usb: gadget: f_uac2: remove platform driver/device creation
Simplify f_uac2 by removing platform driver/device creation; use composite's usb_gadget device as parent for sound card and for debug prints. This removes extra layer of code without any functional change. Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/function/f_uac2.c | 107 +-- 1 file changed, 28 insertions(+), 79 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index f6a0d3a..d4565b5 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -13,7 +13,6 @@ #include #include -#include #include #include @@ -51,8 +50,6 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -static const char *uac2_name = "snd_uac2"; - struct uac2_req { struct uac2_rtd_params *pp; /* parent param */ struct usb_request *req; @@ -81,9 +78,6 @@ struct uac2_rtd_params { }; struct snd_uac2_chip { - struct platform_device pdev; - struct platform_driver pdrv; - struct uac2_rtd_params p_prm; struct uac2_rtd_params c_prm; @@ -122,6 +116,7 @@ struct audio_dev { struct usb_ep *in_ep, *out_ep; struct usb_function func; + struct usb_gadget *gadget; /* The ALSA Sound Card it represents on the USB-Client side */ struct snd_uac2_chip uac2; @@ -140,12 +135,6 @@ struct audio_dev *uac2_to_agdev(struct snd_uac2_chip *u) } static inline -struct snd_uac2_chip *pdev_to_uac2(struct platform_device *p) -{ - return container_of(p, struct snd_uac2_chip, pdev); -} - -static inline struct f_uac2_opts *agdev_to_uac2_opts(struct audio_dev *agdev) { return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); @@ -254,7 +243,7 @@ uint num_channels(uint chanmask) exit: if (usb_ep_queue(ep, req, GFP_ATOMIC)) - dev_err(>pdev.dev, "%d Error!\n", __LINE__); + dev_err(uac2->card->dev, "%d Error!\n", __LINE__); if (update_alsa) snd_pcm_period_elapsed(substream); @@ -440,23 +429,22 @@ static int uac2_pcm_null(struct snd_pcm_substream *substream) .prepare = uac2_pcm_null, }; -static int snd_uac2_probe(struct platform_device *pdev) +static int snd_uac2_probe(struct audio_dev *audio_dev) { - struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev); + struct snd_uac2_chip *uac2 = _dev->uac2; struct snd_card *card; struct snd_pcm *pcm; - struct audio_dev *audio_dev; struct f_uac2_opts *opts; int err; int p_chmask, c_chmask; - audio_dev = uac2_to_agdev(uac2); opts = container_of(audio_dev->func.fi, struct f_uac2_opts, func_inst); p_chmask = opts->p_chmask; c_chmask = opts->c_chmask; /* Choose any slot, with no id */ - err = snd_card_new(>dev, -1, NULL, THIS_MODULE, 0, ); + err = snd_card_new(_dev->gadget->dev, + -1, NULL, THIS_MODULE, 0, ); if (err < 0) return err; @@ -481,16 +469,15 @@ static int snd_uac2_probe(struct platform_device *pdev) strcpy(card->driver, "UAC2_Gadget"); strcpy(card->shortname, "UAC2_Gadget"); - sprintf(card->longname, "UAC2_Gadget %i", pdev->id); + sprintf(card->longname, "UAC2_Gadget %i", card->dev->id); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); err = snd_card_register(card); - if (!err) { - platform_set_drvdata(pdev, card); + + if (!err) return 0; - } snd_fail: snd_card_free(card); @@ -501,9 +488,9 @@ static int snd_uac2_probe(struct platform_device *pdev) return err; } -static int snd_uac2_remove(struct platform_device *pdev) +static int snd_uac2_remove(struct audio_dev *audio_dev) { - struct snd_card *card = platform_get_drvdata(pdev); + struct snd_card *card = audio_dev->uac2.card; if (card) return snd_card_free(card); @@ -511,45 +498,6 @@ static int snd_uac2_remove(struct platform_device *pdev) return 0; } -static void snd_uac2_release(struct device *dev) -{ - dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); -} - -static int alsa_uac2_init(struct audio_dev *agdev) -{ - struct snd_uac2_chip *uac2 = >uac2; - int err; - - uac2->pdrv.probe = snd_uac2_probe; - uac2->pdrv.remove = snd_uac2_remove; - uac2->pdrv.driver.name = uac2_name; - - uac2->pdev.id = 0; - uac2->pdev.name = uac2_name; - uac2->pdev.dev.release = snd_uac2_release; - - /* Register snd_uac2 driver */ - err = platform_driver_register(>pdrv); - if (err) -
Re: [PATCH v3 0/3] USB Audio Gadget refactoring
Hi Felipe, On Mon, Aug 29, 2016 at 11:05 AM, Felipe Balbi <ba...@kernel.org> wrote: > > Hi, > > Ruslan Bilovol <ruslan.bilo...@gmail.com> writes: >> I came to this patch series when wanted to do two things: >> - use UAC1 as virtual ALSA sound card on gadget side, >>just like UAC2 is used so it's possible to do rate >>resampling >> - have both playback/capture support in UAC1 >> >> Since I wanted to have same behavior for both UAC1/UAC2, >> obviously I've got an utility part (u_audio.c) for >> virtual ALSA sound card handling like we have >> for ethernet(u_ether) or serial(u_serial) functions. >> Function-specific parts (f_uac1/f_uac2) became almost >> as storage for class-specific USB descriptors, some >> boilerplate for configfs, binding and few USB >> config request handling. >> >> Originally in RFC [1] I've posted before, there was >> major change to f_uac1 after that it couldn't do >> direct play to existing ALSA sound card anymore, >> representing audio on gadget side as virtual >> ALSA sound card where audio streams are simply >> sinked to and sourced from it, so it may break >> current usecase for some people (and that's why >> it was RFC). >> >> During RFC discussion, it was agreed to not touch >> existing f_uac1 implementation and create new one >> instead. This patchset (v2) introduced new function >> named f_uac1_newapi and doesn't touch current f_uac1 >> implementation, so people still can use old behavior >> >> Now, it's possible to use existing user-space >> applications for audio routing between Audio Gadget >> and real sound card. I personally use alsaloop tool >> from alsautils and have ability to create PCM >> loopback between two different ALSA cards using >> rate resampling, which was not possible with previous >> "direct play to ALSA card" approach in f_uac1. >> >> While here, also dropped redundant platform >> driver/device creation in f_uac2 driver (as well as >> didn't add "never implemented" volume/mute functionality >> in f_uac1 to f_uac1_newapi) that made this work even >> easier to do. >> >> This series is tested with both legacy g_audio.ko and >> modern configfs approaches under Ubuntu 14.04 (UAC1 and >> UAC2) and under Windows7 x64 (UAC1 only) having >> perfect results in all cases. >> >> Comments, testing are welcome. >> >> v3 changes: >> - renamed u_audio exported symbols so they don't >>conflict with old f_uac1 if both are built-in. >> >> v2 changes: >> - do not touch f_uac1, instead created f_uac1_newapi > > f_uac1_newapi What the hell man? :-s Yes, sometimes it's difficult to create laconic name that shows difference to old f_uac1. We can name it alternatively "f_uac1_alsa" or maybe anybody else have good idea here. I just wanted to show here that it's f_uac1 with completely different functionality (expose ALSA card to userspace instead of consuming existing one) > > Sure you can't change f_uac1 to newapi without introducing userland > visible changes? We really don't want to add another copy of f_uac1, > sorry. Do you mean same f_uac1.ko module will be able to use existing ALSA card (old api) and create it own as well (new api) in the same time at runtime? By the way, while I understand your desire to not introduce userland visible changes, in this particular case it doesn't make much sense, since that's, again, two opposite approaches to consume and transfer data to userspace Moreover, now old f_uac1 and new f_uac1_newapi have different functionality exposed to host (first one has only playback, second one - playback+capture), so even USB descriptors are different. So userspace compatibility in this case will make f_uac1 driver too difficult to maintain and add new functionality. So I prefer to keep the new version of f_uac1 function and let it move forward with new features. Best regards, Ruslan -- 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 v3 0/3] USB Audio Gadget refactoring
I came to this patch series when wanted to do two things: - use UAC1 as virtual ALSA sound card on gadget side, just like UAC2 is used so it's possible to do rate resampling - have both playback/capture support in UAC1 Since I wanted to have same behavior for both UAC1/UAC2, obviously I've got an utility part (u_audio.c) for virtual ALSA sound card handling like we have for ethernet(u_ether) or serial(u_serial) functions. Function-specific parts (f_uac1/f_uac2) became almost as storage for class-specific USB descriptors, some boilerplate for configfs, binding and few USB config request handling. Originally in RFC [1] I've posted before, there was major change to f_uac1 after that it couldn't do direct play to existing ALSA sound card anymore, representing audio on gadget side as virtual ALSA sound card where audio streams are simply sinked to and sourced from it, so it may break current usecase for some people (and that's why it was RFC). During RFC discussion, it was agreed to not touch existing f_uac1 implementation and create new one instead. This patchset (v2) introduced new function named f_uac1_newapi and doesn't touch current f_uac1 implementation, so people still can use old behavior Now, it's possible to use existing user-space applications for audio routing between Audio Gadget and real sound card. I personally use alsaloop tool from alsautils and have ability to create PCM loopback between two different ALSA cards using rate resampling, which was not possible with previous "direct play to ALSA card" approach in f_uac1. While here, also dropped redundant platform driver/device creation in f_uac2 driver (as well as didn't add "never implemented" volume/mute functionality in f_uac1 to f_uac1_newapi) that made this work even easier to do. This series is tested with both legacy g_audio.ko and modern configfs approaches under Ubuntu 14.04 (UAC1 and UAC2) and under Windows7 x64 (UAC1 only) having perfect results in all cases. Comments, testing are welcome. v3 changes: - renamed u_audio exported symbols so they don't conflict with old f_uac1 if both are built-in. v2 changes: - do not touch f_uac1, instead created f_uac1_newapi - added documentation for f_uac1_newapi - rebased on top of v4.8-rc1 [1] https://lkml.org/lkml/2016/5/23/649 Ruslan Bilovol (3): usb: gadget: f_uac2: remove platform driver/device creation usb: gadget: f_uac2: split out audio core usb: gadget: add f_uac1 variant based on new u_audio api .../ABI/testing/configfs-usb-gadget-uac1_newapi| 12 + Documentation/usb/gadget-testing.txt | 41 ++ drivers/usb/gadget/Kconfig | 25 + drivers/usb/gadget/function/Makefile | 3 + drivers/usb/gadget/function/f_uac1_newapi.c| 795 + drivers/usb/gadget/function/f_uac2.c | 778 +++- drivers/usb/gadget/function/u_audio.c | 632 drivers/usb/gadget/function/u_audio.h | 93 +++ drivers/usb/gadget/function/u_uac1_newapi.h| 39 + drivers/usb/gadget/legacy/Kconfig | 14 +- drivers/usb/gadget/legacy/audio.c | 52 ++ 11 files changed, 1801 insertions(+), 683 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi create mode 100644 drivers/usb/gadget/function/f_uac1_newapi.c create mode 100644 drivers/usb/gadget/function/u_audio.c create mode 100644 drivers/usb/gadget/function/u_audio.h create mode 100644 drivers/usb/gadget/function/u_uac1_newapi.h -- 1.9.1 -- 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 v3 1/3] usb: gadget: f_uac2: remove platform driver/device creation
Simplify f_uac2 by removing platform driver/device creation; use composite's usb_gadget device as parent for sound card and for debug prints. This removes extra layer of code without any functional change. Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/function/f_uac2.c | 107 +-- 1 file changed, 28 insertions(+), 79 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index cd214ec8..e14628c 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -13,7 +13,6 @@ #include #include -#include #include #include @@ -54,8 +53,6 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -static const char *uac2_name = "snd_uac2"; - struct uac2_req { struct uac2_rtd_params *pp; /* parent param */ struct usb_request *req; @@ -84,9 +81,6 @@ struct uac2_rtd_params { }; struct snd_uac2_chip { - struct platform_device pdev; - struct platform_driver pdrv; - struct uac2_rtd_params p_prm; struct uac2_rtd_params c_prm; @@ -125,6 +119,7 @@ struct audio_dev { struct usb_ep *in_ep, *out_ep; struct usb_function func; + struct usb_gadget *gadget; /* The ALSA Sound Card it represents on the USB-Client side */ struct snd_uac2_chip uac2; @@ -143,12 +138,6 @@ struct audio_dev *uac2_to_agdev(struct snd_uac2_chip *u) } static inline -struct snd_uac2_chip *pdev_to_uac2(struct platform_device *p) -{ - return container_of(p, struct snd_uac2_chip, pdev); -} - -static inline struct f_uac2_opts *agdev_to_uac2_opts(struct audio_dev *agdev) { return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); @@ -257,7 +246,7 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req) exit: if (usb_ep_queue(ep, req, GFP_ATOMIC)) - dev_err(>pdev.dev, "%d Error!\n", __LINE__); + dev_err(uac2->card->dev, "%d Error!\n", __LINE__); if (update_alsa) snd_pcm_period_elapsed(substream); @@ -441,23 +430,22 @@ static struct snd_pcm_ops uac2_pcm_ops = { .prepare = uac2_pcm_null, }; -static int snd_uac2_probe(struct platform_device *pdev) +static int snd_uac2_probe(struct audio_dev *audio_dev) { - struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev); + struct snd_uac2_chip *uac2 = _dev->uac2; struct snd_card *card; struct snd_pcm *pcm; - struct audio_dev *audio_dev; struct f_uac2_opts *opts; int err; int p_chmask, c_chmask; - audio_dev = uac2_to_agdev(uac2); opts = container_of(audio_dev->func.fi, struct f_uac2_opts, func_inst); p_chmask = opts->p_chmask; c_chmask = opts->c_chmask; /* Choose any slot, with no id */ - err = snd_card_new(>dev, -1, NULL, THIS_MODULE, 0, ); + err = snd_card_new(_dev->gadget->dev, + -1, NULL, THIS_MODULE, 0, ); if (err < 0) return err; @@ -482,16 +470,15 @@ static int snd_uac2_probe(struct platform_device *pdev) strcpy(card->driver, "UAC2_Gadget"); strcpy(card->shortname, "UAC2_Gadget"); - sprintf(card->longname, "UAC2_Gadget %i", pdev->id); + sprintf(card->longname, "UAC2_Gadget %i", card->dev->id); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); err = snd_card_register(card); - if (!err) { - platform_set_drvdata(pdev, card); + + if (!err) return 0; - } snd_fail: snd_card_free(card); @@ -502,9 +489,9 @@ snd_fail: return err; } -static int snd_uac2_remove(struct platform_device *pdev) +static int snd_uac2_remove(struct audio_dev *audio_dev) { - struct snd_card *card = platform_get_drvdata(pdev); + struct snd_card *card = audio_dev->uac2.card; if (card) return snd_card_free(card); @@ -512,45 +499,6 @@ static int snd_uac2_remove(struct platform_device *pdev) return 0; } -static void snd_uac2_release(struct device *dev) -{ - dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); -} - -static int alsa_uac2_init(struct audio_dev *agdev) -{ - struct snd_uac2_chip *uac2 = >uac2; - int err; - - uac2->pdrv.probe = snd_uac2_probe; - uac2->pdrv.remove = snd_uac2_remove; - uac2->pdrv.driver.name = uac2_name; - - uac2->pdev.id = 0; - uac2->pdev.name = uac2_name; - uac2->pdev.dev.release = snd_uac2_release; - - /* Register snd_uac2 driver */ - err = platform_driver_register(>pdrv); - if (err) - return err; - -
[PATCH v3 3/3] usb: gadget: add f_uac1 variant based on new u_audio api
This patch adds new function f_uac1_newapi that uses recently created u_audio api. This makes f_uac1_newapi implementation much simpler by reusing existing u_audio core utilities. This also drops previous f_uac1 approach (write audio samples directly to existing ALSA sound card) and moves to more generic/flexible one - create an f_uac1 ALSA sound card that represents USB Audio function and allows to be used by userspace tools. f_uac1_newapi also has capture support (gadget->host). By default, capture interface has 48000kHz/2ch configuration, same as playback channel has. f_uac1_newapi descriptors naming conventios uses f_uac2 driver naming convention that makes it more common and meaningful. Comparing to f_uac1, the f_uac1_newapi doesn't have volume/mute functionality. This is because the volume/mute feature unit was dummy implementation since that driver creation (2009) and never had real volume control or mute functionality. g_audio can be built using one of existing uac functions (f_uac1, f_uac1_newapi or f_uac2) Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- .../ABI/testing/configfs-usb-gadget-uac1_newapi| 12 + Documentation/usb/gadget-testing.txt | 41 ++ drivers/usb/gadget/Kconfig | 21 + drivers/usb/gadget/function/Makefile | 2 + drivers/usb/gadget/function/f_uac1_newapi.c| 795 + drivers/usb/gadget/function/u_uac1_newapi.h| 39 + drivers/usb/gadget/legacy/Kconfig | 15 +- drivers/usb/gadget/legacy/audio.c | 52 ++ 8 files changed, 975 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi create mode 100644 drivers/usb/gadget/function/f_uac1_newapi.c create mode 100644 drivers/usb/gadget/function/u_uac1_newapi.h diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi b/Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi new file mode 100644 index 000..d355275 --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi @@ -0,0 +1,12 @@ +What: /config/usb-gadget/gadget/functions/uac1_newapi.name +Date: Aug 2016 +KernelVersion: 4.9 +Description: + The attributes: + + c_chmask - capture channel mask + c_srate - capture sampling rate + c_ssize - capture sample size (bytes) + p_chmask - playback channel mask + p_srate - playback sampling rate + p_ssize - playback sample size (bytes) diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index 5819605..4598d7f 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -20,6 +20,7 @@ provided by gadgets. 17. UAC2 function 18. UVC function 19. PRINTER function +20. UAC1 function (new API) 1. ACM function @@ -770,3 +771,43 @@ host: More advanced testing can be done with the prn_example described in Documentation/usb/gadget-printer.txt. + + +20. UAC1 function (new API, using u_audio) += + +The function is provided by usb_f_uac1_newapi.ko module. + +Function-specific configfs interface + + +The function name to use when creating the function directory +is "uac1_newapi". The uac1_newapi function provides these attributes +in its function directory: + + c_chmask - capture channel mask + c_srate - capture sampling rate + c_ssize - capture sample size (bytes) + p_chmask - playback channel mask + p_srate - playback sampling rate + p_ssize - playback sample size (bytes) + +The attributes have sane default values. + +Testing the UAC1 function +- + +device: run the gadget +host: aplay -l # should list our USB Audio Gadget + +This function does not require real hardware support, it just +sends a stream of audio data to/from the host. In order to +actually hear something at the device side, a command similar +to this must be used at the device side: + +$ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 & + +e.g.: + +$ arecord -f dat -t wav -D hw:CARD=UAC1Gadget,DEV=0 | \ +aplay -D default:CARD=OdroidU3 diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index a25afd8..abcb539 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -194,6 +194,9 @@ config USB_F_FS config USB_F_UAC1 tristate +config USB_F_UAC1_NEWAPI + tristate + config USB_F_UAC2 tristate @@ -397,6 +400,24 @@ config USB_CONFIGFS_F_UAC1 This driver requires a real Audio codec to be present on the device. +config USB_CONFIGFS_F_UAC1_NEWAPI + bool "Audio Class 1.0 (new API)" + depends on USB_CONFIGFS + depends on SND + select USB_LIBCOMPOSITE + select SND_PCM + select USB_U_AUDIO + sele
[PATCH v3 2/3] usb: gadget: f_uac2: split out audio core
Abstract the peripheral side ALSA sound card code from the f_uac2 function into a component that can be called by various functions, so the various flavors can be split apart and selectively reused. Visible changes: - add uac_params structure to pass audio paramteres for g_audio_setup - make ALSA sound card's name configurable - add [in/out]_ep_maxpsize - allocate snd_uac_chip structure during g_audio_setup - add u_audio_[start/stop]_[capture/playback] functions Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/Kconfig| 4 + drivers/usb/gadget/function/Makefile | 1 + drivers/usb/gadget/function/f_uac2.c | 699 -- drivers/usb/gadget/function/u_audio.c | 632 ++ drivers/usb/gadget/function/u_audio.h | 93 + drivers/usb/gadget/legacy/Kconfig | 1 + 6 files changed, 813 insertions(+), 617 deletions(-) create mode 100644 drivers/usb/gadget/function/u_audio.c create mode 100644 drivers/usb/gadget/function/u_audio.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3c3f31c..a25afd8 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -158,6 +158,9 @@ config USB_U_SERIAL config USB_U_ETHER tristate +config USB_U_AUDIO + tristate + config USB_F_SERIAL tristate @@ -400,6 +403,7 @@ config USB_CONFIGFS_F_UAC2 depends on SND select USB_LIBCOMPOSITE select SND_PCM + select USB_U_AUDIO select USB_F_UAC2 help This Audio function is compatible with USB Audio Class diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index cb8c225..b29f2ae 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -32,6 +32,7 @@ usb_f_mass_storage-y := f_mass_storage.o storage_common.o obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o usb_f_fs-y := f_fs.o obj-$(CONFIG_USB_F_FS) += usb_f_fs.o +obj-$(CONFIG_USB_U_AUDIO) += u_audio.o usb_f_uac1-y := f_uac1.o u_uac1.o obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o usb_f_uac2-y := f_uac2.o diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index e14628c..ef8e976 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -15,15 +15,9 @@ #include #include -#include -#include -#include - +#include "u_audio.h" #include "u_uac2.h" -/* Keep everyone on toes */ -#define USB_XFERS 2 - /* * The driver implements a simple UAC_2 topology. * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture @@ -53,453 +47,23 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -struct uac2_req { - struct uac2_rtd_params *pp; /* parent param */ - struct usb_request *req; -}; - -struct uac2_rtd_params { - struct snd_uac2_chip *uac2; /* parent chip */ - bool ep_enabled; /* if the ep is enabled */ - /* Size of the ring buffer */ - size_t dma_bytes; - unsigned char *dma_area; - - struct snd_pcm_substream *ss; - - /* Ring buffer */ - ssize_t hw_ptr; - - void *rbuf; - - size_t period_size; - - unsigned max_psize; - struct uac2_req ureq[USB_XFERS]; - - spinlock_t lock; -}; - -struct snd_uac2_chip { - struct uac2_rtd_params p_prm; - struct uac2_rtd_params c_prm; - - struct snd_card *card; - struct snd_pcm *pcm; - - /* timekeeping for the playback endpoint */ - unsigned int p_interval; - unsigned int p_residue; - - /* pre-calculated values for playback iso completion */ - unsigned int p_pktsize; - unsigned int p_pktsize_residue; - unsigned int p_framesize; -}; - -#define BUFF_SIZE_MAX (PAGE_SIZE * 16) -#define PRD_SIZE_MAX PAGE_SIZE -#define MIN_PERIODS4 - -static struct snd_pcm_hardware uac2_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER -| SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID -| SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, - .rates = SNDRV_PCM_RATE_CONTINUOUS, - .periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX, - .buffer_bytes_max = BUFF_SIZE_MAX, - .period_bytes_max = PRD_SIZE_MAX, - .periods_min = MIN_PERIODS, -}; - -struct audio_dev { - u8 ac_intf, ac_alt; - u8 as_out_intf, as_out_alt; - u8 as_in_intf, as_in_alt; - - struct usb_ep *in_ep, *out_ep; - struct usb_function func; - struct usb_gadget *gadget; - - /* The ALSA Sound Card it represents on the USB-Client side */ - struct snd_uac2_chip uac2; +struct f_uac2 { + struct g_audio g_audio; + u8 ac_intf, as_in_intf, as_out_intf; + u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_al
Re: [PATCH v2 2/3] usb: gadget: f_uac2: split out audio core
On Tue, Aug 16, 2016 at 9:20 PM, kbuild test robot <l...@intel.com> wrote: > Hi Ruslan, > > [auto build test ERROR on balbi-usb/next] > [also build test ERROR on v4.8-rc2 next-20160816] > [if your patch is applied to the wrong git tree, please drop us a note to > help improve the system] > > url: > https://github.com/0day-ci/linux/commits/Ruslan-Bilovol/USB-Audio-Gadget-refactoring/20160814-185318 > base: https://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git next > config: x86_64-randconfig-a0-08162223 (attached as .config) > compiler: gcc-4.4 (Debian 4.4.7-8) 4.4.7 > reproduce: > # save the attached .config to linux build tree > make ARCH=x86_64 > > All errors (new ones prefixed by >>): > >drivers/usb/gadget/function/usb_f_uac1.o: In function `gaudio_setup': >>> (.text+0x16ce): multiple definition of `gaudio_setup' >drivers/usb/gadget/function/u_audio.o:u_audio.c:(.text+0x937): first > defined here >drivers/usb/gadget/function/usb_f_uac1.o: In function `gaudio_cleanup': >>> (.text+0x1147): multiple definition of `gaudio_cleanup' >drivers/usb/gadget/function/u_audio.o:u_audio.c:(.text+0x3f): first > defined here > Arrgh, it now conflicts in this patchset where we keep old f_uac1 functionality. Will fix it in next patchset. Best regards, Ruslan -- 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 v2 0/3] USB Audio Gadget refactoring
On Tue, Aug 16, 2016 at 12:16 PM, Peter Chen <hzpeterc...@gmail.com> wrote: > On Sun, Aug 14, 2016 at 01:21:21AM +0300, Ruslan Bilovol wrote: >> I came to this patch series when wanted to do two things: >> - use UAC1 as virtual ALSA sound card on gadget side, >>just like UAC2 is used so it's possible to do rate >>resampling >> - have both playback/capture support in UAC1 >> >> Since I wanted to have same behavior for both UAC1/UAC2, >> obviously I've got an utility part (u_audio.c) for >> virtual ALSA sound card handling like we have >> for ethernet(u_ether) or serial(u_serial) functions. >> Function-specific parts (f_uac1/f_uac2) became almost >> as storage for class-specific USB descriptors, some >> boilerplate for configfs, binding and few USB >> config request handling. >> >> Originally in RFC [1] I've posted before, there was >> major change to f_uac1 after that it couldn't do >> direct play to existing ALSA sound card anymore, >> representing audio on gadget side as virtual >> ALSA sound card where audio streams are simply >> sinked to and sourced from it, so it may break >> current usecase for some people (and that's why >> it was RFC). >> >> During RFC discussion, it was agreed to not touch >> existing f_uac1 implementation and create new one >> instead. This patchset (v2) introduced new function >> named f_uac1_newapi and doesn't touch current f_uac1 >> implementation, so people still can use old behavior >> >> Now, it's possible to use existing user-space >> applications for audio routing between Audio Gadget >> and real sound card. I personally use alsaloop tool >> from alsautils and have ability to create PCM >> loopback between two different ALSA cards using >> rate resampling, which was not possible with previous >> "direct play to ALSA card" approach in f_uac1. >> >> While here, also dropped redundant platform >> driver/device creation in f_uac2 driver (as well as >> didn't add "never implemented" volume/mute functionality >> in f_uac1 to f_uac1_newapi) that made this work even >> easier to do. >> >> This series is tested with both legacy g_audio.ko and >> modern configfs approaches under Ubuntu 14.04 (UAC1 and >> UAC2) and under Windows7 x64 (UAC1 only) having >> perfect results in all cases. >> > > I find UAC2 (UAC1 is ok) support is not well with the latest mainline > kernel w/o your patch set. The windows7 can't install the driver > successfully and the playback shows underrun (using local codec) > using Linux host. As Clemens already pointed, Windows 7 doesn't have UAC2 support "out of the box". That's why I tested only UAC1 on it. > > Do you use the unchanged mainline kernel? Yes, this patchset is based on v4.8-rc1 tag. > > My configfs parameters like below: > echo 2 > functions/uac2.1/c_ssize > echo 48000 > functions/uac2.1/c_srate > echo 3 > functions/uac2.1/c_chmask > echo 2 > functions/uac2.1/p_ssize > echo 48000 > functions/uac2.1/p_srate > echo 3 > functions/uac2.1/p_chmask I usually don't change these (use default values here) I use BeagleBone Black for this patchset verification. Here is how I configure it through configfs: uac_2 mkdir cfg mount none cfg -t configfs mkdir cfg/usb_gadget/g1 cd cfg/usb_gadget/g1 mkdir configs/c.1 mkdir functions/uac2.0 mkdir strings/0x409 mkdir configs/c.1/strings/0x409 echo 0x0101 > idProduct echo 0x1d6b > idVendor echo my-serial-num > strings/0x409/serialnumber echo my-manufacturer > strings/0x409/manufacturer echo "Test gadget" > strings/0x409/product echo "Conf 1" > configs/c.1/strings/0x409/configuration echo 120 > configs/c.1/MaxPower ln -s functions/uac2.0 configs/c.1 echo musb-hdrc.0.auto > UDC uac_1 (new api) - mkdir cfg mount none cfg -t configfs mkdir cfg/usb_gadget/g1 cd cfg/usb_gadget/g1 mkdir configs/c.1 mkdir functions/uac1_newapi.0 mkdir strings/0x409 mkdir configs/c.1/strings/0x409 echo 0x0101 > idProduct echo 0x1d6b > idVendor echo my-serial-num > strings/0x409/serialnumber echo my-manufacturer > strings/0x409/manufacturer echo "Test gadget" > strings/0x409/product echo "Conf 1" > configs/c.1/strings/0x409/configuration echo 120 > configs/c.1/MaxPower ln -s functions/uac1_newapi.0 configs/c.1 echo musb-hdrc.0.auto > UDC > > > Console output: > root@imx6qdlsolo:~# arecord -f dat -t wav -D hw:1,0 | aplay -D hw:0,0 & > [1] 859 > root@imx6qdlsolo:~# > root@imx6qdlsolo:~# Recording WAVE 'stdin' : Signed 16 bit Little > Endian, Rate 48000 Hz, Stereo > Playing WAVE 'stdin' : Signed 1
Re: [PATCH v2 3/3] usb: gadget: add f_uac1 variant based on new u_audio api
On Tue, Aug 16, 2016 at 5:52 AM, Peter Chen <hzpeterc...@gmail.com> wrote: > On Sun, Aug 14, 2016 at 01:21:24AM +0300, Ruslan Bilovol wrote: >> This patch adds new function f_uac1_newapi that >> uses recently created u_audio api. This makes >> f_uac1_newapi implementation much simpler by >> reusing existing u_audio core utilities. >> >> This also drops previous f_uac1 approach (write >> audio samples directly to existing ALSA sound >> card) and moves to more generic/flexible >> one - create an f_uac1 ALSA sound card that >> represents USB Audio function and allows to >> be used by userspace tools. >> >> f_uac1_newapi also has capture support (gadget->host). >> By default, capture interface has 48000kHz/2ch >> configuration, same as playback channel has. >> >> f_uac1_newapi descriptors naming conventios >> uses f_uac2 driver naming convention that >> makes it more common and meaningful. >> >> Comparing to f_uac1, the f_uac1_newapi doesn't >> have volume/mute functionality. This is because >> the volume/mute feature unit was dummy >> implementation since that driver creation (2009) >> and never had real volume control or mute >> functionality. >> >> g_audio can be built using one of existing >> uac functions (f_uac1, f_uac1_newapi or f_uac2) >> >> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> >> --- >> .../ABI/testing/configfs-usb-gadget-uac1_newapi| 12 + >> Documentation/usb/gadget-testing.txt | 41 ++ >> drivers/usb/gadget/Kconfig | 21 + >> drivers/usb/gadget/function/Makefile | 2 + >> drivers/usb/gadget/function/f_uac1_newapi.c| 795 >> + >> drivers/usb/gadget/function/u_uac1_newapi.h| 39 + >> drivers/usb/gadget/legacy/Kconfig | 15 +- >> drivers/usb/gadget/legacy/audio.c | 52 ++ >> 8 files changed, 975 insertions(+), 2 deletions(-) >> create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi >> create mode 100644 drivers/usb/gadget/function/f_uac1_newapi.c >> create mode 100644 drivers/usb/gadget/function/u_uac1_newapi.h >> >> diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi >> b/Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi >> new file mode 100644 >> index 000..d355275 >> --- /dev/null >> +++ b/Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi >> @@ -0,0 +1,12 @@ >> +What:/config/usb-gadget/gadget/functions/uac1_newapi.name >> +Date:Aug 2016 >> +KernelVersion: 4.9 >> +Description: >> + The attributes: >> + >> + c_chmask - capture channel mask >> + c_srate - capture sampling rate >> + c_ssize - capture sample size (bytes) >> + p_chmask - playback channel mask >> + p_srate - playback sampling rate >> + p_ssize - playback sample size (bytes) >> diff --git a/Documentation/usb/gadget-testing.txt >> b/Documentation/usb/gadget-testing.txt >> index 5819605..4598d7f 100644 >> --- a/Documentation/usb/gadget-testing.txt >> +++ b/Documentation/usb/gadget-testing.txt >> @@ -20,6 +20,7 @@ provided by gadgets. >> 17. UAC2 function >> 18. UVC function >> 19. PRINTER function >> +20. UAC1 function (new API) >> >> >> 1. ACM function >> @@ -770,3 +771,43 @@ host: >> >> More advanced testing can be done with the prn_example >> described in Documentation/usb/gadget-printer.txt. >> + >> + >> +20. UAC1 function (new API, using u_audio) >> += >> + >> +The function is provided by usb_f_uac1_newapi.ko module. >> + >> +Function-specific configfs interface >> + >> + >> +The function name to use when creating the function directory >> +is "uac1_newapi". The uac1_newapi function provides these attributes >> +in its function directory: >> + >> + c_chmask - capture channel mask >> + c_srate - capture sampling rate >> + c_ssize - capture sample size (bytes) >> + p_chmask - playback channel mask >> + p_srate - playback sampling rate >> + p_ssize - playback sample size (bytes) >> + >> +The attributes have sane default values. >> + >> +Testing the UAC1 function >> +- >> + >> +device: run the gadget >> +host: aplay
[PATCH v2 1/3] usb: gadget: f_uac2: remove platform driver/device creation
Simplify f_uac2 by removing platform driver/device creation; use composite's usb_gadget device as parent for sound card and for debug prints. This removes extra layer of code without any functional change. Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/function/f_uac2.c | 107 +-- 1 file changed, 28 insertions(+), 79 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index cd214ec8..e14628c 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -13,7 +13,6 @@ #include #include -#include #include #include @@ -54,8 +53,6 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -static const char *uac2_name = "snd_uac2"; - struct uac2_req { struct uac2_rtd_params *pp; /* parent param */ struct usb_request *req; @@ -84,9 +81,6 @@ struct uac2_rtd_params { }; struct snd_uac2_chip { - struct platform_device pdev; - struct platform_driver pdrv; - struct uac2_rtd_params p_prm; struct uac2_rtd_params c_prm; @@ -125,6 +119,7 @@ struct audio_dev { struct usb_ep *in_ep, *out_ep; struct usb_function func; + struct usb_gadget *gadget; /* The ALSA Sound Card it represents on the USB-Client side */ struct snd_uac2_chip uac2; @@ -143,12 +138,6 @@ struct audio_dev *uac2_to_agdev(struct snd_uac2_chip *u) } static inline -struct snd_uac2_chip *pdev_to_uac2(struct platform_device *p) -{ - return container_of(p, struct snd_uac2_chip, pdev); -} - -static inline struct f_uac2_opts *agdev_to_uac2_opts(struct audio_dev *agdev) { return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); @@ -257,7 +246,7 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req) exit: if (usb_ep_queue(ep, req, GFP_ATOMIC)) - dev_err(>pdev.dev, "%d Error!\n", __LINE__); + dev_err(uac2->card->dev, "%d Error!\n", __LINE__); if (update_alsa) snd_pcm_period_elapsed(substream); @@ -441,23 +430,22 @@ static struct snd_pcm_ops uac2_pcm_ops = { .prepare = uac2_pcm_null, }; -static int snd_uac2_probe(struct platform_device *pdev) +static int snd_uac2_probe(struct audio_dev *audio_dev) { - struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev); + struct snd_uac2_chip *uac2 = _dev->uac2; struct snd_card *card; struct snd_pcm *pcm; - struct audio_dev *audio_dev; struct f_uac2_opts *opts; int err; int p_chmask, c_chmask; - audio_dev = uac2_to_agdev(uac2); opts = container_of(audio_dev->func.fi, struct f_uac2_opts, func_inst); p_chmask = opts->p_chmask; c_chmask = opts->c_chmask; /* Choose any slot, with no id */ - err = snd_card_new(>dev, -1, NULL, THIS_MODULE, 0, ); + err = snd_card_new(_dev->gadget->dev, + -1, NULL, THIS_MODULE, 0, ); if (err < 0) return err; @@ -482,16 +470,15 @@ static int snd_uac2_probe(struct platform_device *pdev) strcpy(card->driver, "UAC2_Gadget"); strcpy(card->shortname, "UAC2_Gadget"); - sprintf(card->longname, "UAC2_Gadget %i", pdev->id); + sprintf(card->longname, "UAC2_Gadget %i", card->dev->id); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); err = snd_card_register(card); - if (!err) { - platform_set_drvdata(pdev, card); + + if (!err) return 0; - } snd_fail: snd_card_free(card); @@ -502,9 +489,9 @@ snd_fail: return err; } -static int snd_uac2_remove(struct platform_device *pdev) +static int snd_uac2_remove(struct audio_dev *audio_dev) { - struct snd_card *card = platform_get_drvdata(pdev); + struct snd_card *card = audio_dev->uac2.card; if (card) return snd_card_free(card); @@ -512,45 +499,6 @@ static int snd_uac2_remove(struct platform_device *pdev) return 0; } -static void snd_uac2_release(struct device *dev) -{ - dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); -} - -static int alsa_uac2_init(struct audio_dev *agdev) -{ - struct snd_uac2_chip *uac2 = >uac2; - int err; - - uac2->pdrv.probe = snd_uac2_probe; - uac2->pdrv.remove = snd_uac2_remove; - uac2->pdrv.driver.name = uac2_name; - - uac2->pdev.id = 0; - uac2->pdev.name = uac2_name; - uac2->pdev.dev.release = snd_uac2_release; - - /* Register snd_uac2 driver */ - err = platform_driver_register(>pdrv); - if (err) - return err; - -
[PATCH v2 3/3] usb: gadget: add f_uac1 variant based on new u_audio api
This patch adds new function f_uac1_newapi that uses recently created u_audio api. This makes f_uac1_newapi implementation much simpler by reusing existing u_audio core utilities. This also drops previous f_uac1 approach (write audio samples directly to existing ALSA sound card) and moves to more generic/flexible one - create an f_uac1 ALSA sound card that represents USB Audio function and allows to be used by userspace tools. f_uac1_newapi also has capture support (gadget->host). By default, capture interface has 48000kHz/2ch configuration, same as playback channel has. f_uac1_newapi descriptors naming conventios uses f_uac2 driver naming convention that makes it more common and meaningful. Comparing to f_uac1, the f_uac1_newapi doesn't have volume/mute functionality. This is because the volume/mute feature unit was dummy implementation since that driver creation (2009) and never had real volume control or mute functionality. g_audio can be built using one of existing uac functions (f_uac1, f_uac1_newapi or f_uac2) Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- .../ABI/testing/configfs-usb-gadget-uac1_newapi| 12 + Documentation/usb/gadget-testing.txt | 41 ++ drivers/usb/gadget/Kconfig | 21 + drivers/usb/gadget/function/Makefile | 2 + drivers/usb/gadget/function/f_uac1_newapi.c| 795 + drivers/usb/gadget/function/u_uac1_newapi.h| 39 + drivers/usb/gadget/legacy/Kconfig | 15 +- drivers/usb/gadget/legacy/audio.c | 52 ++ 8 files changed, 975 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi create mode 100644 drivers/usb/gadget/function/f_uac1_newapi.c create mode 100644 drivers/usb/gadget/function/u_uac1_newapi.h diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi b/Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi new file mode 100644 index 000..d355275 --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi @@ -0,0 +1,12 @@ +What: /config/usb-gadget/gadget/functions/uac1_newapi.name +Date: Aug 2016 +KernelVersion: 4.9 +Description: + The attributes: + + c_chmask - capture channel mask + c_srate - capture sampling rate + c_ssize - capture sample size (bytes) + p_chmask - playback channel mask + p_srate - playback sampling rate + p_ssize - playback sample size (bytes) diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index 5819605..4598d7f 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -20,6 +20,7 @@ provided by gadgets. 17. UAC2 function 18. UVC function 19. PRINTER function +20. UAC1 function (new API) 1. ACM function @@ -770,3 +771,43 @@ host: More advanced testing can be done with the prn_example described in Documentation/usb/gadget-printer.txt. + + +20. UAC1 function (new API, using u_audio) += + +The function is provided by usb_f_uac1_newapi.ko module. + +Function-specific configfs interface + + +The function name to use when creating the function directory +is "uac1_newapi". The uac1_newapi function provides these attributes +in its function directory: + + c_chmask - capture channel mask + c_srate - capture sampling rate + c_ssize - capture sample size (bytes) + p_chmask - playback channel mask + p_srate - playback sampling rate + p_ssize - playback sample size (bytes) + +The attributes have sane default values. + +Testing the UAC1 function +- + +device: run the gadget +host: aplay -l # should list our USB Audio Gadget + +This function does not require real hardware support, it just +sends a stream of audio data to/from the host. In order to +actually hear something at the device side, a command similar +to this must be used at the device side: + +$ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 & + +e.g.: + +$ arecord -f dat -t wav -D hw:CARD=UAC1Gadget,DEV=0 | \ +aplay -D default:CARD=OdroidU3 diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index a25afd8..abcb539 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -194,6 +194,9 @@ config USB_F_FS config USB_F_UAC1 tristate +config USB_F_UAC1_NEWAPI + tristate + config USB_F_UAC2 tristate @@ -397,6 +400,24 @@ config USB_CONFIGFS_F_UAC1 This driver requires a real Audio codec to be present on the device. +config USB_CONFIGFS_F_UAC1_NEWAPI + bool "Audio Class 1.0 (new API)" + depends on USB_CONFIGFS + depends on SND + select USB_LIBCOMPOSITE + select SND_PCM + select USB_U_AUDIO + sele
[PATCH v2 2/3] usb: gadget: f_uac2: split out audio core
Abstract the peripheral side ALSA sound card code from the f_uac2 function into a component that can be called by various functions, so the various flavors can be split apart and selectively reused. Visible changes: - add uac_params structure to pass audio paramteres for gaudio_setup - make ALSA sound card's name configurable - add [in/out]_ep_maxpsize - allocate snd_uac_chip structure during gaudio_setup - add gaudio_[start/stop]_[capture/playback] functions Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/Kconfig| 4 + drivers/usb/gadget/function/Makefile | 1 + drivers/usb/gadget/function/f_uac2.c | 699 -- drivers/usb/gadget/function/u_audio.c | 632 ++ drivers/usb/gadget/function/u_audio.h | 93 + drivers/usb/gadget/legacy/Kconfig | 1 + 6 files changed, 813 insertions(+), 617 deletions(-) create mode 100644 drivers/usb/gadget/function/u_audio.c create mode 100644 drivers/usb/gadget/function/u_audio.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3c3f31c..a25afd8 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -158,6 +158,9 @@ config USB_U_SERIAL config USB_U_ETHER tristate +config USB_U_AUDIO + tristate + config USB_F_SERIAL tristate @@ -400,6 +403,7 @@ config USB_CONFIGFS_F_UAC2 depends on SND select USB_LIBCOMPOSITE select SND_PCM + select USB_U_AUDIO select USB_F_UAC2 help This Audio function is compatible with USB Audio Class diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index cb8c225..b29f2ae 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -32,6 +32,7 @@ usb_f_mass_storage-y := f_mass_storage.o storage_common.o obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o usb_f_fs-y := f_fs.o obj-$(CONFIG_USB_F_FS) += usb_f_fs.o +obj-$(CONFIG_USB_U_AUDIO) += u_audio.o usb_f_uac1-y := f_uac1.o u_uac1.o obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o usb_f_uac2-y := f_uac2.o diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index e14628c..2cf1495 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -15,15 +15,9 @@ #include #include -#include -#include -#include - +#include "u_audio.h" #include "u_uac2.h" -/* Keep everyone on toes */ -#define USB_XFERS 2 - /* * The driver implements a simple UAC_2 topology. * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture @@ -53,453 +47,23 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -struct uac2_req { - struct uac2_rtd_params *pp; /* parent param */ - struct usb_request *req; -}; - -struct uac2_rtd_params { - struct snd_uac2_chip *uac2; /* parent chip */ - bool ep_enabled; /* if the ep is enabled */ - /* Size of the ring buffer */ - size_t dma_bytes; - unsigned char *dma_area; - - struct snd_pcm_substream *ss; - - /* Ring buffer */ - ssize_t hw_ptr; - - void *rbuf; - - size_t period_size; - - unsigned max_psize; - struct uac2_req ureq[USB_XFERS]; - - spinlock_t lock; -}; - -struct snd_uac2_chip { - struct uac2_rtd_params p_prm; - struct uac2_rtd_params c_prm; - - struct snd_card *card; - struct snd_pcm *pcm; - - /* timekeeping for the playback endpoint */ - unsigned int p_interval; - unsigned int p_residue; - - /* pre-calculated values for playback iso completion */ - unsigned int p_pktsize; - unsigned int p_pktsize_residue; - unsigned int p_framesize; -}; - -#define BUFF_SIZE_MAX (PAGE_SIZE * 16) -#define PRD_SIZE_MAX PAGE_SIZE -#define MIN_PERIODS4 - -static struct snd_pcm_hardware uac2_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER -| SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID -| SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, - .rates = SNDRV_PCM_RATE_CONTINUOUS, - .periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX, - .buffer_bytes_max = BUFF_SIZE_MAX, - .period_bytes_max = PRD_SIZE_MAX, - .periods_min = MIN_PERIODS, -}; - -struct audio_dev { - u8 ac_intf, ac_alt; - u8 as_out_intf, as_out_alt; - u8 as_in_intf, as_in_alt; - - struct usb_ep *in_ep, *out_ep; - struct usb_function func; - struct usb_gadget *gadget; - - /* The ALSA Sound Card it represents on the USB-Client side */ - struct snd_uac2_chip uac2; +struct f_uac2 { + struct gaudio gaudio; + u8 ac_intf, as_in_intf, as_out_intf; + u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_al
[PATCH v2 0/3] USB Audio Gadget refactoring
I came to this patch series when wanted to do two things: - use UAC1 as virtual ALSA sound card on gadget side, just like UAC2 is used so it's possible to do rate resampling - have both playback/capture support in UAC1 Since I wanted to have same behavior for both UAC1/UAC2, obviously I've got an utility part (u_audio.c) for virtual ALSA sound card handling like we have for ethernet(u_ether) or serial(u_serial) functions. Function-specific parts (f_uac1/f_uac2) became almost as storage for class-specific USB descriptors, some boilerplate for configfs, binding and few USB config request handling. Originally in RFC [1] I've posted before, there was major change to f_uac1 after that it couldn't do direct play to existing ALSA sound card anymore, representing audio on gadget side as virtual ALSA sound card where audio streams are simply sinked to and sourced from it, so it may break current usecase for some people (and that's why it was RFC). During RFC discussion, it was agreed to not touch existing f_uac1 implementation and create new one instead. This patchset (v2) introduced new function named f_uac1_newapi and doesn't touch current f_uac1 implementation, so people still can use old behavior Now, it's possible to use existing user-space applications for audio routing between Audio Gadget and real sound card. I personally use alsaloop tool from alsautils and have ability to create PCM loopback between two different ALSA cards using rate resampling, which was not possible with previous "direct play to ALSA card" approach in f_uac1. While here, also dropped redundant platform driver/device creation in f_uac2 driver (as well as didn't add "never implemented" volume/mute functionality in f_uac1 to f_uac1_newapi) that made this work even easier to do. This series is tested with both legacy g_audio.ko and modern configfs approaches under Ubuntu 14.04 (UAC1 and UAC2) and under Windows7 x64 (UAC1 only) having perfect results in all cases. Comments, testing are welcome. v2 changes: - do not touch f_uac1, instead created f_uac1_newapi - added documentation for f_uac1_newapi - rebased on top of v4.8-rc1 [1] https://lkml.org/lkml/2016/5/23/649 Ruslan Bilovol (3): usb: gadget: f_uac2: remove platform driver/device creation usb: gadget: f_uac2: split out audio core usb: gadget: add f_uac1 variant based on new u_audio api .../ABI/testing/configfs-usb-gadget-uac1_newapi| 12 + Documentation/usb/gadget-testing.txt | 41 ++ drivers/usb/gadget/Kconfig | 25 + drivers/usb/gadget/function/Makefile | 3 + drivers/usb/gadget/function/f_uac1_newapi.c| 795 + drivers/usb/gadget/function/f_uac2.c | 778 +++- drivers/usb/gadget/function/u_audio.c | 632 drivers/usb/gadget/function/u_audio.h | 93 +++ drivers/usb/gadget/function/u_uac1_newapi.h| 39 + drivers/usb/gadget/legacy/Kconfig | 14 +- drivers/usb/gadget/legacy/audio.c | 56 +- 11 files changed, 1803 insertions(+), 685 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uac1_newapi create mode 100644 drivers/usb/gadget/function/f_uac1_newapi.c create mode 100644 drivers/usb/gadget/function/u_audio.c create mode 100644 drivers/usb/gadget/function/u_audio.h create mode 100644 drivers/usb/gadget/function/u_uac1_newapi.h -- 1.9.1 -- 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: [RFC PATCH 0/5] USB Audio Gadget refactoring
On Tue, Jul 26, 2016 at 3:02 PM, Krzysztof Opasiak <k.opas...@samsung.com> wrote: > > > On 07/26/2016 10:53 AM, Jassi Brar wrote: >> On Tue, Jul 26, 2016 at 7:01 AM, Ruslan Bilovol >> <ruslan.bilo...@gmail.com> wrote: >>> On Fri, Jul 15, 2016 at 10:43 AM, Clemens Ladisch <clem...@ladisch.de> >>> wrote: >>>>>> On Tue, May 24, 2016 at 2:50 AM, Ruslan Bilovol >>>>>> <ruslan.bilo...@gmail.com> wrote: >>>>>>> it may break current usecase for some people >>>> >>>> And what are the benefits that justify breaking the kernel API? >>> >>> >>> Main limitation with current f_uac1 design is - it can be used only on >>> systems >>> with real ALSA card present and can have only exact number of >>> channels / sampling rate as sink card has. >>> Yet it is not flexible - can't do audio processing between f_uac1 and the >>> card. >>> Also if someone wants to bind f_uac1 it to another sound card he has to >>> unload g_audio or reconfigure it through configfs - that means USB >>> reenumeration on host device. >>> >>> If you have a "virtual sound card", audio processing is done in userspace >>> and is more flexible. You even don't need to have a real sound card and >>> can use some userspace application for playing/capturing audio samples. >>> Moreover, existing f_uac2 (that is USB Audio Class 2.0 function >>> implementation) already uses approach of "virtual sound card" >>> >> While I agree the virtual sound card approach is the right way, I am >> not sure if we should break the userspace api that the existing UAC1 >> driver exposes. Maybe we should add another virtual-sound-card >> exposing UAC1 driver ... and hopefully very similar to (or just port >> of) the f_audio_source.c from android. > > Definitely agree with this opinion. I don't see any benefits of breaking > the API here instead of adding just another USB function. Maybe even > some pieces of code could be shared with f_uac1.c but I think that this > should be a brand new function. > So if we want to keep old API working, easiest (and cleanest) way is to create a new f_uac1.c version and kconfig symbol, for example f_uac1_newapi.c and CONFIG_USB_F_UAC1_NEWAPI There is no sence to share some pieces of code with f_uac1.c just because it is changed too drastically. So I'll implement it in v2 if there is no any objections Best regards, Ruslan Bilovol -- 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: [RFC PATCH 0/5] USB Audio Gadget refactoring
On Tue, Jul 26, 2016 at 11:53 AM, Jassi Brar <jassisinghb...@gmail.com> wrote: > On Tue, Jul 26, 2016 at 7:01 AM, Ruslan Bilovol > <ruslan.bilo...@gmail.com> wrote: >> On Fri, Jul 15, 2016 at 10:43 AM, Clemens Ladisch <clem...@ladisch.de> wrote: >>>>> On Tue, May 24, 2016 at 2:50 AM, Ruslan Bilovol >>>>> <ruslan.bilo...@gmail.com> wrote: >>>>>> it may break current usecase for some people >>> >>> And what are the benefits that justify breaking the kernel API? >> >> >> Main limitation with current f_uac1 design is - it can be used only on >> systems >> with real ALSA card present and can have only exact number of >> channels / sampling rate as sink card has. >> Yet it is not flexible - can't do audio processing between f_uac1 and the >> card. >> Also if someone wants to bind f_uac1 it to another sound card he has to >> unload g_audio or reconfigure it through configfs - that means USB >> reenumeration on host device. >> >> If you have a "virtual sound card", audio processing is done in userspace >> and is more flexible. You even don't need to have a real sound card and >> can use some userspace application for playing/capturing audio samples. >> Moreover, existing f_uac2 (that is USB Audio Class 2.0 function >> implementation) already uses approach of "virtual sound card" >> > While I agree the virtual sound card approach is the right way, I am > not sure if we should break the userspace api that the existing UAC1 > driver exposes. Maybe we should add another virtual-sound-card > exposing UAC1 driver This approach is quite easy to implement and I though about it when started to work on this patch series, but due to my lazyness I wanted to get some comments before doing extra work. > ... and hopefully very similar to (or just port > of) the f_audio_source.c from android. Current patch series reuses code from f_uac2 (in u_audio) and makes it in some sense similar to f_audio_source.c. The f_audio_source.c implementation has additional functionality like more accurate data transferring (w.r.t timings), that can be ported to u_audio separately. Best regards, Ruslan -- 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: [RFC PATCH 0/5] USB Audio Gadget refactoring
On Fri, Jul 15, 2016 at 10:43 AM, Clemens Ladisch <clem...@ladisch.de> wrote: >>> On Tue, May 24, 2016 at 2:50 AM, Ruslan Bilovol >>> <ruslan.bilo...@gmail.com> wrote: >>>> it may break current usecase for some people > > And what are the benefits that justify breaking the kernel API? Main limitation with current f_uac1 design is - it can be used only on systems with real ALSA card present and can have only exact number of channels / sampling rate as sink card has. Yet it is not flexible - can't do audio processing between f_uac1 and the card. Also if someone wants to bind f_uac1 it to another sound card he has to unload g_audio or reconfigure it through configfs - that means USB reenumeration on host device. If you have a "virtual sound card", audio processing is done in userspace and is more flexible. You even don't need to have a real sound card and can use some userspace application for playing/capturing audio samples. Moreover, existing f_uac2 (that is USB Audio Class 2.0 function implementation) already uses approach of "virtual sound card" A real cases when it's required to have UAC1 gadget represented as virtual sound card on gadget side: - android accessory f_audio_source.c implementation, android plays audio directly to UAC1 "virtual sound card" - some 3G/LTE voice USB sticks with Linux as firmware have user-space application inside that receives audio from network and need to source/sink it to some sound card (UAC1) - USB sound card with complex audio processing inside, made on small Linux-powered device ("sound-studio") What's annoying is we have two quite similar USB Audio Classes implementations(f_uac1 and f_uac2) that have opposite audio representations: first transfers audio samples directly to real ALSA card, second exposes virtual ALSA card. That means you have to implement similar things (capture/playback, etc) in different way. With new design both implementations provide same "API" (virtual sound card), allowing us to reuse a lot of code and implement new features much easier (look at adding of capture support to f_uac1 in PATCH 5/5 - that was very simple and consists almost from adding new USB descriptors and reusing existing code from newly created u_audio.c) Also new USB Audio Gadget design follows existing approach for another USB Classes: - serial gadgets use u_serial and expose virtual TTY port - networking gadgets use u_ether and expose virtual network interface - uvc gadget exposes virtual v4l device - midi gadget exposes virtual sound card - etc, etc Of course disadvantage of new approach for UAC1 gadget is you need to use some userspace application for routing audio from virtual to real sound card, like in case of UAC2 gadget. But thanks to existing applications like alsaloop it's not difficult nowadays. The answer I want to get in this RFC - can we drop current f_uac1 approach, simplify USB Audio Gadget by reusing common code. Or "we do not break userspace" (or API) and have to live with it forever. Best regards, Ruslan -- 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: [RFC PATCH 0/5] USB Audio Gadget refactoring
Ping? On Wed, Jun 8, 2016 at 11:03 AM, Ruslan Bilovol <ruslan.bilo...@gmail.com> wrote: > Hi guys, > > Any feedback on this patch series? Has anybody had a chance to test it? > > Regards, > Ruslan > > On Tue, May 24, 2016 at 2:50 AM, Ruslan Bilovol > <ruslan.bilo...@gmail.com> wrote: >> I came to this patch series when wanted to do two things: >> - use UAC1 as virtual ALSA sound card on gadget side, >>just like UAC2 is used so it's possible to do rate >>resampling >> - have both playback/capture support in UAC1 >> >> Since I wanted to have same behavior for both UAC1/UAC2, >> obviously I've got an utility part (u_audio.c) for >> virtual ALSA sound card handling like we have >> for ethernet(u_ether) or serial(u_serial) functions. >> Function-specific parts (f_uac1/f_uac2) became almost >> as storage for class-specfic USB descriptors, some >> boilerplate for configfs, binding and few USB >> config request handling. >> >> Major change to f_uac1 it that it can't do >> direct play to existing ALSA sound card anymore, >> representing audio on gadget side as virtual >> ALSA sound card where audio streams are simply >> sinked to and sourced from it, so it may break >> current usecase for some people (and that's why >> it's RFC). >> >> Luckily, it's possible to use existing user-space >> applications for audio routing between Audio Gadget >> and real sound card. I personally use alsaloop tool >> from alsautils and have ability to create PCM >> loopback between two different ALSA cards using >> rate resampling, which is not possible with previous >> "direct play to ALSA card" approach in f_uac1. >> >> While here, also dropped redundant platform >> driver/device creation in f_uac2 driver as well as >> "never implemented" volume/mute functionality in f_uac1 >> that made this work even easier to do. >> >> This series is tested with both legacy g_audio.ko and >> modern configfs approaches under Ubuntu 14.04 (UAC1 and >> UAC2) and under Windows7 x64 (UAC1 only) having >> perfect results in all cases. >> >> Some changes may have lack of good description that may >> be obvious for me but not so clear for others, but I >> hope to fix it in next versions. >> >> Comments, testing are welcome. >> >> Ruslan Bilovol (5): >> usb: gadget: f_uac2: remove platform driver/device creation >> usb: gadget: f_uac2: split out audio core >> usb: gadget: f_uac1: drop volume/mute functionality >> usb: gadget: f_uac1: switch to u_audio core utilities >> usb: gadget: f_uac1: add capture support >> >> drivers/usb/gadget/Kconfig| 13 +- >> drivers/usb/gadget/function/Makefile | 3 +- >> drivers/usb/gadget/function/f_uac1.c | 842 >> +- >> drivers/usb/gadget/function/f_uac2.c | 778 --- >> drivers/usb/gadget/function/u_audio.c | 632 + >> drivers/usb/gadget/function/u_audio.h | 93 >> drivers/usb/gadget/function/u_uac1.c | 314 - >> drivers/usb/gadget/function/u_uac1.h | 71 +-- >> drivers/usb/gadget/legacy/Kconfig | 1 + >> drivers/usb/gadget/legacy/audio.c | 54 ++- >> 10 files changed, 1208 insertions(+), 1593 deletions(-) >> create mode 100644 drivers/usb/gadget/function/u_audio.c >> create mode 100644 drivers/usb/gadget/function/u_audio.h >> delete mode 100644 drivers/usb/gadget/function/u_uac1.c >> >> -- >> 1.9.1 >> -- 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: [RFC PATCH 0/5] USB Audio Gadget refactoring
Hi guys, Any feedback on this patch series? Has anybody had a chance to test it? Regards, Ruslan On Tue, May 24, 2016 at 2:50 AM, Ruslan Bilovol <ruslan.bilo...@gmail.com> wrote: > I came to this patch series when wanted to do two things: > - use UAC1 as virtual ALSA sound card on gadget side, >just like UAC2 is used so it's possible to do rate >resampling > - have both playback/capture support in UAC1 > > Since I wanted to have same behavior for both UAC1/UAC2, > obviously I've got an utility part (u_audio.c) for > virtual ALSA sound card handling like we have > for ethernet(u_ether) or serial(u_serial) functions. > Function-specific parts (f_uac1/f_uac2) became almost > as storage for class-specfic USB descriptors, some > boilerplate for configfs, binding and few USB > config request handling. > > Major change to f_uac1 it that it can't do > direct play to existing ALSA sound card anymore, > representing audio on gadget side as virtual > ALSA sound card where audio streams are simply > sinked to and sourced from it, so it may break > current usecase for some people (and that's why > it's RFC). > > Luckily, it's possible to use existing user-space > applications for audio routing between Audio Gadget > and real sound card. I personally use alsaloop tool > from alsautils and have ability to create PCM > loopback between two different ALSA cards using > rate resampling, which is not possible with previous > "direct play to ALSA card" approach in f_uac1. > > While here, also dropped redundant platform > driver/device creation in f_uac2 driver as well as > "never implemented" volume/mute functionality in f_uac1 > that made this work even easier to do. > > This series is tested with both legacy g_audio.ko and > modern configfs approaches under Ubuntu 14.04 (UAC1 and > UAC2) and under Windows7 x64 (UAC1 only) having > perfect results in all cases. > > Some changes may have lack of good description that may > be obvious for me but not so clear for others, but I > hope to fix it in next versions. > > Comments, testing are welcome. > > Ruslan Bilovol (5): > usb: gadget: f_uac2: remove platform driver/device creation > usb: gadget: f_uac2: split out audio core > usb: gadget: f_uac1: drop volume/mute functionality > usb: gadget: f_uac1: switch to u_audio core utilities > usb: gadget: f_uac1: add capture support > > drivers/usb/gadget/Kconfig| 13 +- > drivers/usb/gadget/function/Makefile | 3 +- > drivers/usb/gadget/function/f_uac1.c | 842 > +- > drivers/usb/gadget/function/f_uac2.c | 778 --- > drivers/usb/gadget/function/u_audio.c | 632 + > drivers/usb/gadget/function/u_audio.h | 93 > drivers/usb/gadget/function/u_uac1.c | 314 - > drivers/usb/gadget/function/u_uac1.h | 71 +-- > drivers/usb/gadget/legacy/Kconfig | 1 + > drivers/usb/gadget/legacy/audio.c | 54 ++- > 10 files changed, 1208 insertions(+), 1593 deletions(-) > create mode 100644 drivers/usb/gadget/function/u_audio.c > create mode 100644 drivers/usb/gadget/function/u_audio.h > delete mode 100644 drivers/usb/gadget/function/u_uac1.c > > -- > 1.9.1 > -- 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
[RFC PATCH 3/5] usb: gadget: f_uac1: drop volume/mute functionality
The volume/mute feature unit was dummy implementation since this driver creation (2009) and never had real volume control or mute functionality. Since it was never implemented, drop it and increase maintainability of the driver. Those who want real volume/mute support may revert this patch and add needed handlers Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/function/f_uac1.c | 182 +-- 1 file changed, 5 insertions(+), 177 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index f2ac0cb..ba498af 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -17,9 +17,6 @@ #include "u_uac1.h" -static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value); -static int generic_get_cmd(struct usb_audio_control *con, u8 cmd); - /* * DESCRIPTORS ... most are static, but strings and full * configuration descriptors are built on demand. @@ -49,9 +46,9 @@ static struct usb_interface_descriptor ac_interface_desc = { DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); #define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) -/* 1 input terminal, 1 output terminal and 1 feature unit */ +/* 1 input terminal and 1 output terminal */ #define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \ - + UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0)) + + UAC_DT_OUTPUT_TERMINAL_SIZE) /* B.3.2 Class-Specific AC Interface Descriptor */ static struct uac1_ac_header_descriptor_1 ac_header_desc = { .bLength = UAC_DT_AC_HEADER_LENGTH, @@ -77,54 +74,15 @@ static struct uac_input_terminal_descriptor input_terminal_desc = { .wChannelConfig = 0x3, }; -DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0); - -#define FEATURE_UNIT_ID2 -static struct uac_feature_unit_descriptor_0 feature_unit_desc = { - .bLength= UAC_DT_FEATURE_UNIT_SIZE(0), - .bDescriptorType= USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_FEATURE_UNIT, - .bUnitID= FEATURE_UNIT_ID, - .bSourceID = INPUT_TERMINAL_ID, - .bControlSize = 2, - .bmaControls[0] = (UAC_FU_MUTE | UAC_FU_VOLUME), -}; - -static struct usb_audio_control mute_control = { - .list = LIST_HEAD_INIT(mute_control.list), - .name = "Mute Control", - .type = UAC_FU_MUTE, - /* Todo: add real Mute control code */ - .set = generic_set_cmd, - .get = generic_get_cmd, -}; - -static struct usb_audio_control volume_control = { - .list = LIST_HEAD_INIT(volume_control.list), - .name = "Volume Control", - .type = UAC_FU_VOLUME, - /* Todo: add real Volume control code */ - .set = generic_set_cmd, - .get = generic_get_cmd, -}; - -static struct usb_audio_control_selector feature_unit = { - .list = LIST_HEAD_INIT(feature_unit.list), - .id = FEATURE_UNIT_ID, - .name = "Mute & Volume Control", - .type = UAC_FEATURE_UNIT, - .desc = (struct usb_descriptor_header *)_unit_desc, -}; - -#define OUTPUT_TERMINAL_ID 3 +#define OUTPUT_TERMINAL_ID 2 static struct uac1_output_terminal_descriptor output_terminal_desc = { .bLength= UAC_DT_OUTPUT_TERMINAL_SIZE, .bDescriptorType= USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, .bTerminalID= OUTPUT_TERMINAL_ID, .wTerminalType = UAC_OUTPUT_TERMINAL_SPEAKER, - .bAssocTerminal = FEATURE_UNIT_ID, - .bSourceID = FEATURE_UNIT_ID, + .bAssocTerminal = 0, + .bSourceID = INPUT_TERMINAL_ID, }; /* B.4.1 Standard AS Interface Descriptor */ @@ -195,7 +153,6 @@ static struct usb_descriptor_header *f_audio_desc[] = { (struct usb_descriptor_header *)_terminal_desc, (struct usb_descriptor_header *)_terminal_desc, - (struct usb_descriptor_header *)_unit_desc, (struct usb_descriptor_header *)_interface_alt_0_desc, (struct usb_descriptor_header *)_interface_alt_1_desc, @@ -212,7 +169,6 @@ enum { STR_AC_IF, STR_INPUT_TERMINAL, STR_INPUT_TERMINAL_CH_NAMES, - STR_FEAT_DESC_0, STR_OUTPUT_TERMINAL, STR_AS_IF_ALT0, STR_AS_IF_ALT1, @@ -222,7 +178,6 @@ static struct usb_string strings_uac1[] = { [STR_AC_IF].s = "AC Interface", [STR_INPUT_TERMINAL].s = "Input terminal", [STR_INPUT_TERMINAL_CH_NAMES].s = "Channels", - [STR_FEAT_DESC_0].s = "Volume control & mute", [STR_OUTPUT_TERMINAL].s = "Output terminal", [STR_AS_IF_ALT0].s = "AS Interface", [STR_AS_IF_ALT1].s = "AS Interface
[RFC PATCH 2/5] usb: gadget: f_uac2: split out audio core
Abstract the peripheral side ALSA sound card code from the f_uac2 function into a component that can be called by various functions, so the various flavors can be split apart and selectively reused. Visible changes: - add uac_params structure to pass audio paramteres for gaudio_setup - make ALSA sound card's name configurable - add [in/out]_ep_maxpsize - allocate snd_uac_chip structure during gaudio_setup - add gaudio_[start/stop]_[capture/playback] functions Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/Kconfig| 4 + drivers/usb/gadget/function/Makefile | 1 + drivers/usb/gadget/function/f_uac2.c | 699 -- drivers/usb/gadget/function/u_audio.c | 632 ++ drivers/usb/gadget/function/u_audio.h | 93 + drivers/usb/gadget/legacy/Kconfig | 1 + 6 files changed, 813 insertions(+), 617 deletions(-) create mode 100644 drivers/usb/gadget/function/u_audio.c create mode 100644 drivers/usb/gadget/function/u_audio.h diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index af5d922..42d8508 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -157,6 +157,9 @@ config USB_U_SERIAL config USB_U_ETHER tristate +config USB_U_AUDIO + tristate + config USB_F_SERIAL tristate @@ -399,6 +402,7 @@ config USB_CONFIGFS_F_UAC2 depends on SND select USB_LIBCOMPOSITE select SND_PCM + select USB_U_AUDIO select USB_F_UAC2 help This Audio function is compatible with USB Audio Class diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index cb8c225..b29f2ae 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -32,6 +32,7 @@ usb_f_mass_storage-y := f_mass_storage.o storage_common.o obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o usb_f_fs-y := f_fs.o obj-$(CONFIG_USB_F_FS) += usb_f_fs.o +obj-$(CONFIG_USB_U_AUDIO) += u_audio.o usb_f_uac1-y := f_uac1.o u_uac1.o obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o usb_f_uac2-y := f_uac2.o diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 8b46f05..a6c91a6 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -15,15 +15,9 @@ #include #include -#include -#include -#include - +#include "u_audio.h" #include "u_uac2.h" -/* Keep everyone on toes */ -#define USB_XFERS 2 - /* * The driver implements a simple UAC_2 topology. * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture @@ -53,453 +47,23 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -struct uac2_req { - struct uac2_rtd_params *pp; /* parent param */ - struct usb_request *req; -}; - -struct uac2_rtd_params { - struct snd_uac2_chip *uac2; /* parent chip */ - bool ep_enabled; /* if the ep is enabled */ - /* Size of the ring buffer */ - size_t dma_bytes; - unsigned char *dma_area; - - struct snd_pcm_substream *ss; - - /* Ring buffer */ - ssize_t hw_ptr; - - void *rbuf; - - size_t period_size; - - unsigned max_psize; - struct uac2_req ureq[USB_XFERS]; - - spinlock_t lock; -}; - -struct snd_uac2_chip { - struct uac2_rtd_params p_prm; - struct uac2_rtd_params c_prm; - - struct snd_card *card; - struct snd_pcm *pcm; - - /* timekeeping for the playback endpoint */ - unsigned int p_interval; - unsigned int p_residue; - - /* pre-calculated values for playback iso completion */ - unsigned int p_pktsize; - unsigned int p_pktsize_residue; - unsigned int p_framesize; -}; - -#define BUFF_SIZE_MAX (PAGE_SIZE * 16) -#define PRD_SIZE_MAX PAGE_SIZE -#define MIN_PERIODS4 - -static struct snd_pcm_hardware uac2_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER -| SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID -| SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, - .rates = SNDRV_PCM_RATE_CONTINUOUS, - .periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX, - .buffer_bytes_max = BUFF_SIZE_MAX, - .period_bytes_max = PRD_SIZE_MAX, - .periods_min = MIN_PERIODS, -}; - -struct audio_dev { - u8 ac_intf, ac_alt; - u8 as_out_intf, as_out_alt; - u8 as_in_intf, as_in_alt; - - struct usb_ep *in_ep, *out_ep; - struct usb_function func; - struct usb_gadget *gadget; - - /* The ALSA Sound Card it represents on the USB-Client side */ - struct snd_uac2_chip uac2; +struct f_uac2 { + struct gaudio gaudio; + u8 ac_intf, as_in_intf, as_out_intf; + u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_al
[RFC PATCH 0/5] USB Audio Gadget refactoring
I came to this patch series when wanted to do two things: - use UAC1 as virtual ALSA sound card on gadget side, just like UAC2 is used so it's possible to do rate resampling - have both playback/capture support in UAC1 Since I wanted to have same behavior for both UAC1/UAC2, obviously I've got an utility part (u_audio.c) for virtual ALSA sound card handling like we have for ethernet(u_ether) or serial(u_serial) functions. Function-specific parts (f_uac1/f_uac2) became almost as storage for class-specfic USB descriptors, some boilerplate for configfs, binding and few USB config request handling. Major change to f_uac1 it that it can't do direct play to existing ALSA sound card anymore, representing audio on gadget side as virtual ALSA sound card where audio streams are simply sinked to and sourced from it, so it may break current usecase for some people (and that's why it's RFC). Luckily, it's possible to use existing user-space applications for audio routing between Audio Gadget and real sound card. I personally use alsaloop tool from alsautils and have ability to create PCM loopback between two different ALSA cards using rate resampling, which is not possible with previous "direct play to ALSA card" approach in f_uac1. While here, also dropped redundant platform driver/device creation in f_uac2 driver as well as "never implemented" volume/mute functionality in f_uac1 that made this work even easier to do. This series is tested with both legacy g_audio.ko and modern configfs approaches under Ubuntu 14.04 (UAC1 and UAC2) and under Windows7 x64 (UAC1 only) having perfect results in all cases. Some changes may have lack of good description that may be obvious for me but not so clear for others, but I hope to fix it in next versions. Comments, testing are welcome. Ruslan Bilovol (5): usb: gadget: f_uac2: remove platform driver/device creation usb: gadget: f_uac2: split out audio core usb: gadget: f_uac1: drop volume/mute functionality usb: gadget: f_uac1: switch to u_audio core utilities usb: gadget: f_uac1: add capture support drivers/usb/gadget/Kconfig| 13 +- drivers/usb/gadget/function/Makefile | 3 +- drivers/usb/gadget/function/f_uac1.c | 842 +- drivers/usb/gadget/function/f_uac2.c | 778 --- drivers/usb/gadget/function/u_audio.c | 632 + drivers/usb/gadget/function/u_audio.h | 93 drivers/usb/gadget/function/u_uac1.c | 314 - drivers/usb/gadget/function/u_uac1.h | 71 +-- drivers/usb/gadget/legacy/Kconfig | 1 + drivers/usb/gadget/legacy/audio.c | 54 ++- 10 files changed, 1208 insertions(+), 1593 deletions(-) create mode 100644 drivers/usb/gadget/function/u_audio.c create mode 100644 drivers/usb/gadget/function/u_audio.h delete mode 100644 drivers/usb/gadget/function/u_uac1.c -- 1.9.1 -- 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
[RFC PATCH 1/5] usb: gadget: f_uac2: remove platform driver/device creation
Simplify f_uac2 by removing platform driver/device creation; use composite's usb_gadget device as parent for sound card and for debug prints. This removes extra layer of code without any functional change. Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/function/f_uac2.c | 107 +-- 1 file changed, 28 insertions(+), 79 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 186d4b1..8b46f05 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -13,7 +13,6 @@ #include #include -#include #include #include @@ -54,8 +53,6 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -static const char *uac2_name = "snd_uac2"; - struct uac2_req { struct uac2_rtd_params *pp; /* parent param */ struct usb_request *req; @@ -84,9 +81,6 @@ struct uac2_rtd_params { }; struct snd_uac2_chip { - struct platform_device pdev; - struct platform_driver pdrv; - struct uac2_rtd_params p_prm; struct uac2_rtd_params c_prm; @@ -125,6 +119,7 @@ struct audio_dev { struct usb_ep *in_ep, *out_ep; struct usb_function func; + struct usb_gadget *gadget; /* The ALSA Sound Card it represents on the USB-Client side */ struct snd_uac2_chip uac2; @@ -143,12 +138,6 @@ struct audio_dev *uac2_to_agdev(struct snd_uac2_chip *u) } static inline -struct snd_uac2_chip *pdev_to_uac2(struct platform_device *p) -{ - return container_of(p, struct snd_uac2_chip, pdev); -} - -static inline struct f_uac2_opts *agdev_to_uac2_opts(struct audio_dev *agdev) { return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); @@ -257,7 +246,7 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req) exit: if (usb_ep_queue(ep, req, GFP_ATOMIC)) - dev_err(>pdev.dev, "%d Error!\n", __LINE__); + dev_err(uac2->card->dev, "%d Error!\n", __LINE__); if (update_alsa) snd_pcm_period_elapsed(substream); @@ -441,23 +430,22 @@ static struct snd_pcm_ops uac2_pcm_ops = { .prepare = uac2_pcm_null, }; -static int snd_uac2_probe(struct platform_device *pdev) +static int snd_uac2_probe(struct audio_dev *audio_dev) { - struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev); + struct snd_uac2_chip *uac2 = _dev->uac2; struct snd_card *card; struct snd_pcm *pcm; - struct audio_dev *audio_dev; struct f_uac2_opts *opts; int err; int p_chmask, c_chmask; - audio_dev = uac2_to_agdev(uac2); opts = container_of(audio_dev->func.fi, struct f_uac2_opts, func_inst); p_chmask = opts->p_chmask; c_chmask = opts->c_chmask; /* Choose any slot, with no id */ - err = snd_card_new(>dev, -1, NULL, THIS_MODULE, 0, ); + err = snd_card_new(_dev->gadget->dev, + -1, NULL, THIS_MODULE, 0, ); if (err < 0) return err; @@ -482,16 +470,15 @@ static int snd_uac2_probe(struct platform_device *pdev) strcpy(card->driver, "UAC2_Gadget"); strcpy(card->shortname, "UAC2_Gadget"); - sprintf(card->longname, "UAC2_Gadget %i", pdev->id); + sprintf(card->longname, "UAC2_Gadget %i", card->dev->id); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); err = snd_card_register(card); - if (!err) { - platform_set_drvdata(pdev, card); + + if (!err) return 0; - } snd_fail: snd_card_free(card); @@ -502,9 +489,9 @@ snd_fail: return err; } -static int snd_uac2_remove(struct platform_device *pdev) +static int snd_uac2_remove(struct audio_dev *audio_dev) { - struct snd_card *card = platform_get_drvdata(pdev); + struct snd_card *card = audio_dev->uac2.card; if (card) return snd_card_free(card); @@ -512,45 +499,6 @@ static int snd_uac2_remove(struct platform_device *pdev) return 0; } -static void snd_uac2_release(struct device *dev) -{ - dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); -} - -static int alsa_uac2_init(struct audio_dev *agdev) -{ - struct snd_uac2_chip *uac2 = >uac2; - int err; - - uac2->pdrv.probe = snd_uac2_probe; - uac2->pdrv.remove = snd_uac2_remove; - uac2->pdrv.driver.name = uac2_name; - - uac2->pdev.id = 0; - uac2->pdev.name = uac2_name; - uac2->pdev.dev.release = snd_uac2_release; - - /* Register snd_uac2 driver */ - err = platform_driver_register(>pdrv); - if (err) - return err; - -
[RFC PATCH 5/5] usb: gadget: f_uac1: add capture support
Add capture support (gadget->host) to the f_uac1 driver. This requires renaming of some descriptors, enums etc that were used exclusively for playback path. To make it meaningful, f_uac2 driver naming convention has been used. By default, capture interface has 48000kHz/2ch configuration, same as playback channel has. Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/Kconfig | 7 +- drivers/usb/gadget/function/f_uac1.c | 265 --- drivers/usb/gadget/function/u_uac1.h | 6 + drivers/usb/gadget/legacy/audio.c| 18 +++ 4 files changed, 239 insertions(+), 57 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index fd6ee1d..ffe611a 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -395,10 +395,11 @@ config USB_CONFIGFS_F_UAC1 This Audio function implements 1 AudioControl interface, 1 AudioStreaming Interface each for USB-OUT and USB-IN. This driver doesn't expect any real Audio codec to be present - on the device - the audio streams are simply sinked to - a virtual ALSA sound card created. The user-space + on the device - the audio streams are simply sinked to and + sourced from a virtual ALSA sound card created. The user-space application may choose to do whatever it wants with the data - received from the USB Host. + received from the USB Host and choose to provide whatever it + wants as audio data to the USB Host. config USB_CONFIGFS_F_UAC2 bool "Audio Class 2.0" diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 120bba9..fcbf204 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -22,8 +22,8 @@ struct f_uac1 { struct gaudio gaudio; - u8 ac_intf, as_out_intf; - u8 ac_alt, as_out_alt; /* needed for get_alt() */ + u8 ac_intf, as_in_intf, as_out_intf; + u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ }; static inline struct f_uac1 *func_to_uac1(struct usb_function *f) @@ -37,12 +37,17 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f) */ /* - * We have two interfaces- AudioControl and AudioStreaming - * TODO: only supcard playback currently + * We have three interfaces- AudioControl and 2 AudioStreaming + * + * The driver implements a simple UAC_1 topology. + * USB-OUT -> IT_1 -> OT_2 -> ALSA_Capture + * ALSA_Playback -> IT_3 -> OT_4 -> USB-IN */ -#define F_AUDIO_AC_INTERFACE 0 -#define F_AUDIO_AS_INTERFACE 1 -#define F_AUDIO_NUM_INTERFACES 1 +#define F_AUDIO_AC_INTERFACE 0 +#define F_AUDIO_AS_OUT_INTERFACE 1 +#define F_AUDIO_AS_IN_INTERFACE2 +/* Number of streaming interfaces */ +#define F_AUDIO_NUM_INTERFACES 2 /* B.3.1 Standard AC Interface Descriptor */ static struct usb_interface_descriptor ac_interface_desc = { @@ -57,14 +62,14 @@ static struct usb_interface_descriptor ac_interface_desc = { * The number of AudioStreaming and MIDIStreaming interfaces * in the Audio Interface Collection */ -DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); +DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); #define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) -/* 1 input terminal and 1 output terminal */ -#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \ - + UAC_DT_OUTPUT_TERMINAL_SIZE) +/* 2 input terminals and 2 output terminals */ +#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \ + + 2*UAC_DT_INPUT_TERMINAL_SIZE + 2*UAC_DT_OUTPUT_TERMINAL_SIZE) /* B.3.2 Class-Specific AC Interface Descriptor */ -static struct uac1_ac_header_descriptor_1 ac_header_desc = { +static struct uac1_ac_header_descriptor_2 ac_header_desc = { .bLength = UAC_DT_AC_HEADER_LENGTH, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_HEADER, @@ -72,35 +77,76 @@ static struct uac1_ac_header_descriptor_1 ac_header_desc = { .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH), .bInCollection =F_AUDIO_NUM_INTERFACES, .baInterfaceNr = { - /* Interface number of the first AudioStream interface */ + /* Interface number of the AudioStream interfaces */ [0] = 1, + [1] = 2, } }; -#define INPUT_TERMINAL_ID 1 -static struct uac_input_terminal_descriptor input_terminal_desc = { +#define USB_OUT_IT_ID 1 +static struct uac_input_terminal_descriptor usb_out_it_desc = { .bLength = UAC_DT_INPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = INPUT_TERMINAL_ID, + .bTerminalID =
[RFC PATCH 4/5] usb: gadget: f_uac1: switch to u_audio core utilities
Reuse existing u_audio core utilities making f_uac1 much simpler. This also drops previous f_uac1 approach (write audio samples directly to existing ALSA sound card) and moves to more generic/flexible one - create an f_uac1 ALSA sound card that represents USB Audio function and allows to be used by userspace tools. As a side effect, using u_audio it will be much easier to create gadget -> PC Host audio stream in the future Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/usb/gadget/Kconfig | 8 +- drivers/usb/gadget/function/Makefile | 2 +- drivers/usb/gadget/function/f_uac1.c | 431 +++ drivers/usb/gadget/function/u_uac1.c | 314 - drivers/usb/gadget/function/u_uac1.h | 65 +- drivers/usb/gadget/legacy/Kconfig| 2 +- drivers/usb/gadget/legacy/audio.c| 42 ++-- 7 files changed, 162 insertions(+), 702 deletions(-) delete mode 100644 drivers/usb/gadget/function/u_uac1.c diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 42d8508..fd6ee1d 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -389,12 +389,16 @@ config USB_CONFIGFS_F_UAC1 depends on SND select USB_LIBCOMPOSITE select SND_PCM + select USB_U_AUDIO select USB_F_UAC1 help This Audio function implements 1 AudioControl interface, 1 AudioStreaming Interface each for USB-OUT and USB-IN. - This driver requires a real Audio codec to be present - on the device. + This driver doesn't expect any real Audio codec to be present + on the device - the audio streams are simply sinked to + a virtual ALSA sound card created. The user-space + application may choose to do whatever it wants with the data + received from the USB Host. config USB_CONFIGFS_F_UAC2 bool "Audio Class 2.0" diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index b29f2ae..bd9d7d5 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -33,7 +33,7 @@ obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o usb_f_fs-y := f_fs.o obj-$(CONFIG_USB_F_FS) += usb_f_fs.o obj-$(CONFIG_USB_U_AUDIO) += u_audio.o -usb_f_uac1-y := f_uac1.o u_uac1.o +usb_f_uac1-y := f_uac1.o obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o usb_f_uac2-y := f_uac2.o obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index ba498af..120bba9 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -4,6 +4,8 @@ * Copyright (C) 2008 Bryan Wu <coolo...@kernel.org> * Copyright (C) 2008 Analog Devices, Inc * + * Copyright (C) 2016 Ruslan Bilovol <ruslan.bilo...@gmail.com> + * * Enter bugs at http://blackfin.uclinux.org/ * * Licensed under the GPL-2 or later. @@ -15,8 +17,20 @@ #include #include +#include "u_audio.h" #include "u_uac1.h" +struct f_uac1 { + struct gaudio gaudio; + u8 ac_intf, as_out_intf; + u8 ac_alt, as_out_alt; /* needed for get_alt() */ +}; + +static inline struct f_uac1 *func_to_uac1(struct usb_function *f) +{ + return container_of(f, struct f_uac1, gaudio.func); +} + /* * DESCRIPTORS ... most are static, but strings and full * configuration descriptors are built on demand. @@ -198,130 +212,6 @@ static struct usb_gadget_strings *uac1_strings[] = { * This function is an ALSA sound card following USB Audio Class Spec 1.0. */ -/*-*/ -struct f_audio_buf { - u8 *buf; - int actual; - struct list_head list; -}; - -static struct f_audio_buf *f_audio_buffer_alloc(int buf_size) -{ - struct f_audio_buf *copy_buf; - - copy_buf = kzalloc(sizeof *copy_buf, GFP_ATOMIC); - if (!copy_buf) - return ERR_PTR(-ENOMEM); - - copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC); - if (!copy_buf->buf) { - kfree(copy_buf); - return ERR_PTR(-ENOMEM); - } - - return copy_buf; -} - -static void f_audio_buffer_free(struct f_audio_buf *audio_buf) -{ - kfree(audio_buf->buf); - kfree(audio_buf); -} -/*-*/ - -struct f_audio { - struct gaudio card; - - /* endpoints handle full and/or high speeds */ - struct usb_ep *out_ep; - - spinlock_t lock; - struct f_audio_buf *copy_buf; - struct work_struct playback_work; - struct list_head play_queue; -}; - -static inline struct f_audio *func_to_audio(struct usb_function *f)
Re: [PATCH v4] kconfig/symbol.c: handle choice_values that depend on 'm' symbols
Hi, On Thu, Mar 31, 2016 at 1:08 AM, Bin Liu <binml...@gmail.com> wrote: > Hi, > > On Fri, Aug 15, 2014 at 2:37 AM, Dirk Gouders <d...@gouders.net> wrote: >> Bin Liu <binml...@gmail.com> writes: >> >>> Dirk, >>> >>> On Thu, Aug 14, 2014 at 1:52 AM, Dirk Gouders <d...@gouders.net> wrote: >>>> Bin Liu <binml...@gmail.com> writes: >>>> >>>>> All, >>>>> >>>>> On Mon, Nov 18, 2013 at 12:08 PM, Yann E. MORIN <yann.morin.1...@free.fr> >>>>> wrote: >>>>>> Dirk, All, >>>>>> >>>>>> On 2013-11-07 15:05 +0100, Dirk Gouders spake thusly: >>>>>>> If choices consist of choice_values that depend on symbols set to 'm', >>>>>>> those choice_values are not set to 'n' if the choice is changed from >>>>>>> 'm' to 'y' (in which case only one active choice_value is allowed). >>>>>>> Those values are also written to the config file causing modules to be >>>>>>> built when they should not. >>>>>>> >>>>>>> The following config can be used to reproduce and examine the problem; >>>>>>> with the frontend of your choice set "Choice 0" and "Choice 1" to 'm', >>>>>>> then set "Tristate Choice" to 'y' and save the configuration: >>>>>>> >>>>>>> config modules >>>>>>> boolean modules >>>>>>> default y >>>>>>> option modules >>>>>>> >>>>>>> config dependency >>>>>>> tristate "Dependency" >>>>>>> default m >>>>>>> >>>>>>> choice >>>>>>> prompt "Tristate Choice" >>>>>>> default choice0 >>>>>>> >>>>>>> config choice0 >>>>>>> tristate "Choice 0" >>>>>>> >>>>>>> config choice1 >>>>>>> tristate "Choice 1" >>>>>>> depends on dependency >>>>>>> >>>>>>> endchoice >>>>>>> >>>>>>> This patch sets choice_values' visibility that depend on symbols set >>>>>>> to 'm' to 'n' if the corresponding choice is set to 'y'. This makes >>>>>>> them disappear from the choice list and will also cause the >>>>>>> choice_values' value set to 'n' in sym_calc_value() and as a result >>>>>>> they are written as "not set" to the resulting .config file. >>>>>>> >>>>>>> Reported-by: Sebastian Andrzej Siewior <bige...@linutronix.de> >>>>>>> Signed-off-by: Dirk Gouders <d...@gouders.net> >>>>>>> Tested-by: Sebastian Andrzej Siewior <bige...@linutronix.de> >>>>>> >>>>>> Acked-by: "Yann E. MORIN" <yann.morin.1...@free.fr> >>>>>> >>>>>> It will be in my tree soon. Thanks! >>>>> >>>>> I don't see this patch in 3.16 but 3.16 does not have the issue any >>>>> more. Anyone has an idea how the issue got fixed? I am trying to find >>>>> the right patch to backport. >>>> >>>> With the above sample kconfig I still see the issue. How did you >>>> notice the issue got fixed? >>> >>> I did not pay much attention on the above sample kconfig, but just >>> focused on the USB gadget driver kconfig issue initially reported by >>> Sebastian. I saw the issue exists in 3.14, but does not in 3.16, >>> unless I messed up with my test. I will test 3.16 again some time next >>> week. >> >> Hi Bin, >> >> I now also re-tested the initially reported steps to reproduce the >> issue: >> >> >>> in USB gadget menu (that is Device Drivers ---> USB support ---> USB >>> Gadget Support ---> USB Gadget Drivers) I can create a configuration >>> which is "lost". Here is how to reproduce it: >>> >>> - first config two gadgets as M: >>> USB Gadget Drivers >>> Audio Gadget >>> Ethernet Gadget >>> MIDI Gadget >>> >>> save config & leave >>> >>> - now start menu config again and go to the same menu, now select >>> built-in: >>> <*> USB Gadget Drivers (Ethernet Gadget >>> the ethernet gadget is chosen automatically because we can have only >>> one gadget selected. >>> save config & leave >>> >>> - step three, go back to the menu and you will see that everything is >>> as it was (the <*> is ignored). >> >> >> Here, I still see the problem (I was wondering if the issue has been >> solved/gone by a kconfig-file modification). > > This issue was gone since 3.16, but came back again due to commit > 1fd6d08 ARM: omap2plus_defconfig: Enable n900 modem as loadable modules. > I can confirm this issue too, faced it on v4.5 (but didn't try v4.6-rc1 yet) -- Best regards, Ruslan Bilovol -- 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] phy: twl4030-usb: fix musb-hdrc name for non-dt case
musb device is allocated with PLATFORM_DEVID_AUTO, fix incorrect lookup name in non-dt case. This fixes issue with musb initialization on Nokia N900 in boardfile boot mode. Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com> --- drivers/phy/phy-twl4030-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 840f3ea..a48214f 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -735,7 +735,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) } if (pdata) - err = phy_create_lookup(phy, "usb", "musb-hdrc.0"); + err = phy_create_lookup(phy, "usb", "musb-hdrc.0.auto"); if (err) return err; -- 1.9.1 -- 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 v3 1/3] USB: add descriptors from USB Power Delivery spec
On Thu, Mar 10, 2016 at 3:59 PM, Oliver Neukumwrote: > Adding the descriptors of chapter 9.2 of the Power Delivery spec. > > Signed-off-by: Oliver Neukum > --- > include/uapi/linux/usb/ch9.h | 98 > > 1 file changed, 98 insertions(+) > > diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h > index 06d6c62..1046c55 100644 > --- a/include/uapi/linux/usb/ch9.h > +++ b/include/uapi/linux/usb/ch9.h > @@ -914,6 +914,104 @@ struct usb_ssp_cap_descriptor { > } __attribute__((packed)); > > /* > + * USB Power Delivery Capability Descriptor: > + * Defines capabilities for PD > + */ > +/* Defines the various PD Capabilities of this device */ > +#define USB_PD_POWER_DELIVERY_CAPABILITY 0x06 > +/* Provides information on each battery supported by the device */ > +#define USB_PD_BATTERY_INFO_CAPABILITY 0x07 > +/* The Consumer characteristics of a Port on the device */ > +#define USB_PD_PD_CONSUMER_PORT_CAPABILITY 0x08 > +/* The provider characteristics of a Port on the device */ > +#define USB_PD_PD_PROVIDER_PORT_CAPABILITY 0x09 > + > +struct usb_pd_cap_descriptor { > + __u8 bLength; > + __u8 bDescriptorType; > + __u8 bDevCapabilityType; /* set to USB_PD_POWER_DELIVERY_CAPABILITY > */ > + __u8 bReserved; > + __le32 bmAttributes; > +#define USB_PD_CAP_BATTERY_CHARGING(1 << 1) /* supports Battery Charging > specification */ > +#define USB_PD_CAP_USB_PD (1 << 2) /* supports USB Power > Delivery specification */ > +#define USB_PD_CAP_PROVIDER(1 << 3) /* can provide power */ > +#define USB_PD_CAP_CONSUMER(1 << 4) /* can consume power */ > +#define USB_PD_CAP_CHARGING_POLICY (1 << 5) /* supports CHARGING_POLICY > feature */ > +#define USB_PD_CAP_TYPE_C_CURRENT (1 << 6) /* supports power > capabilities defined in the USB Type-C Specification */ > + > +#define USB_PD_CAP_PWR_AC (1 << 8) > +#define USB_PD_CAP_PWR_BAT (1 << 9) > +#define USB_PD_CAP_PWR_USE_V_BUS (1 << 14) Thank you for fixing uSB_xxx here > + > + __le16 bmProviderPorts; /* Bit zero refers to the UFP of the device */ > + __le16 bmConsumerPorts; > + __le16 bcdBCVersion; > + __le16 bcdPDVersion; > + __le16 bcdUSBTypeCVersion; > +} __attribute__((packed)); > + > +struct usb_pd_cap_battery_info_descriptor { > + __u8 bLength; > + __u8 bDescriptorType; > + __u8 bDevCapabilityType; > + /* Index of string descriptor shall contain the user friendly name > for this battery */ > + __u8 iBattery; > + /* Index of string descriptor shall contain the Serial Number String > for this battery */ > + __u8 iSerial; > + __u8 iManufacturer; > + __u8 bBatteryId; /* uniquely identifies this battery in status > Messages */ > + __u8 bReserved; > + /* > +* Shall contain the Battery Charge value above which this > +* battery is considered to be fully charged but not necessarily > +* “topped off.” > +*/ > + __le32 dwChargedThreshold; /* in mWh */ > + /* > +* Shall contain the minimum charge level of this battery such > +* that above this threshold, a device can be assured of being > +* able to power up successfully (see Battery Charging 1.2). > +*/ > + __le32 dwWeakThreshold; /* in mWh */ > + __le32 dwBatteryDesignCapacity; /* in mWh */ > + __le32 dwBatteryLastFullchargeCapacity; /* in mWh */ > +} __attribute__((packed)); > + > +struct usb_pd_cap_consumer_port_descriptor { > + __u8 bLength; > + __u8 bDescriptorType; > + __u8 bDevCapabilityType; > + __u8 bReserved; > + __u8 bmCapabilities; > +/* port will oerate under: */ > +#define uSB_PD_CAP_CONSUMER_BC (1 << 0) /* BC */ > +#define uSB_PD_CAP_CONSUMER_PD (1 << 1) /* PD */ > +#define uSB_PD_CAP_CONSUMER_TYPE_C (1 << 2) /* USB Type-C Current */ However, this typo still exists here ^ > + __le16 wMinVoltage; /* in 50mV units */ > + __le16 wMaxVoltage; /* in 50mV units */ > + __u16 wReserved; > + __le32 dwMaxOperatingPower; /* in 10 mW - operating at steady state */ > + __le32 dwMaxPeakPower; /* in 10mW units - operating at peak power */ > + __le32 dwMaxPeakPowerTime; /* in 100ms units - duration of peak */ > +#define uSB_PD_CAP_CONSUMER_UNKNOWN_PEAK_POWER_TIME 0x and here ^ > +} __attribute__((packed)); > + > +struct usb_pd_cap_provider_port_descriptor { > + __u8 bLength; > + __u8 bDescriptorType; > + __u8 bDevCapabilityType; > + __u8 bReserved1; > + __u8 bmCapabilities; > +/* port will oerate under: */ > +#define uSB_PD_CAP_PROVIDER_BC (1 << 0) /* BC */ > +#define uSB_PD_CAP_PROVIDER_PD (1 << 1) /* PD */ > +#define uSB_PD_CAP_PROVIDER_TYPE_C (1 << 2) /* USB Type-C
Re: [RFC Patch 1/3] USB: add descriptors from USB Power Delivery spec
Hi, On Thu, Mar 10, 2016 at 12:45 PM, Felipe Balbiwrote: > > Hi, > > Oliver Neukum writes: >> [ text/plain ] >> Adding the descriptors of chapter 9.2 of the Power Delivery spec. >> >> Signed-off-by: Oliver Neukum >> --- >> include/uapi/linux/usb/ch9.h | 94 >> >> 1 file changed, 94 insertions(+) >> >> diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h >> index 252ac16..c9f2bc2 100644 >> --- a/include/uapi/linux/usb/ch9.h >> +++ b/include/uapi/linux/usb/ch9.h >> @@ -913,6 +913,100 @@ struct usb_ssp_cap_descriptor { >> } __attribute__((packed)); >> >> /* >> + * USB Power Delivery Capability Descriptor: >> + * Defines capabilities for PD >> + */ >> +#define USB_PD_POWER_DELIVERY_CAPABILITY (0x06) /* Defines the various >> PD Capabilities of this device */ >> +#define USB_PD_BATTERY_INFO_CAPABILITY (0x07) /* Provides >> information on each battery supported by the device */ >> +#define USB_PD_PD_CONSUMER_PORT_CAPABILITY (0x08) /* The Consumer >> characteristics of a Port on the device */ >> +#define USB_PD_PD_PROVIDER_PORT_CAPABILITY (0x09) /* The provider >> characteristics of a Port on the device */ > > any chance you can avoid the extra long lines ? > >> +struct usb_pd_cap_descriptor { >> + __u8 bLength; >> + __u8 bDescriptorType; >> + __u8 bDevCapabilityType; /* set to USB_PD_POWER_DELIVERY_CAPABILITY */ >> + __u8 bReserved; >> + __le32 bmAttributes; >> +#define uSB_PD_CAP_BATTERY_CHARGING ( 1 << 1 ) /* supports Battery >> Charging specification */ >> +#define uSB_PD_CAP_USB_PD( 1 << 2 ) /* supports USB Power >> Delivery specification */ >> +#define uSB_PD_CAP_PROVIDER ( 1 << 3 ) /* can provide power */ >> +#define uSB_PD_CAP_CONSUMER ( 1 << 4 ) /* can consume power */ >> +#define uSB_PD_CAP_CHARGING_POLICY ( 1 << 5 ) /* supports CHARGING_POLICY >> feature */ >> +#define uSB_PD_CAP_TYPE_C_CURRENT( 1 << 6 ) /* supports power >> capabilities defined in the USB Type-C Specification */ >> + >> +#define uSB_PD_CAP_PWR_AC( 1 << 8 ) >> +#define uSB_PD_CAP_PWR_BAT ( 1 << 9 ) >> +#define uSB_PD_CAP_PWR_USE_V_BUS ( 1 << 14 ) > > why the extra spaces inside () ? Also it's not clear why these macro start with lowercase letter (e.g. why uSB_XXX instead of USB_XXX), looks like a typo. > > -- > balbi -- Best regards, Ruslan -- 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: gadgetfs regression (NULL ptr deref) since v4.4-rc7
Hi Vegard, On Mon, Feb 8, 2016 at 1:27 AM, Vegard Nossum <vegard.nos...@oracle.com> wrote: > Hi, > > Using gadgetfs on latest mainline, I get the following NULL pointer > dereference: > > BUG: unable to handle kernel NULL pointer dereference at (null) > IP: [] __list_del_entry+0x29/0xc0 > PGD 34f067 PUD 355067 PMD 0 > Oops: [#1] DEBUG_PAGEALLOC > CPU: 0 PID: 35 Comm: afl-fuzz Not tainted 4.5.0-rc2 #1 > task: 882b1ec0 ti: 8833c000 task.ti: 8833c000 > RIP: 0010:[] [] > __list_del_entry+0x29/0xc0 > RSP: 0018:8833fe30 EFLAGS: 00010207 > RAX: RBX: 8138c108 RCX: dead0200 > RDX: RSI: 0061 RDI: 8138c108 > RBP: 8833fe30 R08: R09: > R10: R11: 0246 R12: 8138b928 > R13: 8138c040 R14: 88000ec0da20 R15: 8833ff58 > FS: 77ff2740() GS:8135d000() knlGS: > CS: 0010 DS: ES: CR0: 80050033 > CR2: CR3: 00335000 CR4: 001406b0 > Stack: > 8833fe48 81138f2d 8138bbd0 8833fe70 > 811c880b 882f3000 88000ec109a0 88298aa0 > 8833fe88 811ce040 8834cdc0 8833feb8 > Call Trace: > [] list_del+0xd/0x30 > [] usb_gadget_unregister_driver+0xdb/0xf0 > [] dev_release+0x20/0x60 > [] __fput+0x4c/0x130 > [] fput+0x9/0x10 > [] task_work_run+0x67/0xa0 > [] exit_to_usermode_loop+0x8f/0xa0 > [] syscall_return_slowpath+0x3d/0x40 > [] int_ret_from_sys_call+0x25/0x8f > Code: ff ff 55 48 8b 07 48 b9 00 01 00 00 00 00 ad de 48 8b 57 08 48 89 e5 > 48 39 c8 74 29 48 b9 00 02 00 00 00 00 ad de 48 39 ca 74 3a <4c> 8b 02 4c 39 > c7 75 52 4c 8b 40 08 4c 39 c7 75 66 48 89 50 08 > RIP [] __list_del_entry+0x29/0xc0 > RSP > CR2: > ---[ end trace e6cfe1de661dcffe ]--- > > Reverting this commit fixes the problem for me: > > commit 855ed04a3758b205e84b269f92d26ab36ed8e2f7 > Author: Ruslan Bilovol <ruslan.bilo...@gmail.com> > Date: Mon Nov 23 09:56:38 2015 +0100 > > usb: gadget: udc-core: independent registration of gadgets and gadget > drivers > > Though I am still seeing some occasional lockups. Thanks, > Original version of this patch had checking of input parameters (see change in usb_gadget_unregister_driver at https://lkml.org/lkml/2015/6/22/559) but this approach was rejected by Alan Stern many times so final version pushed by Marek Szyprowski doesn't have it, and we have this NULL pointer dereference. But this means there is a bug in GadgetFS that was hidden previously: it tries to deregister gadget driver that was not previously registered. Previous implementation was returning -ENODEV retval, current one just does NULL pointer dereference. At least need to fix GadgetFS that seems to by buggy in gadget driver unregistering, and I still say we need to nave input parameters checking in externally visible functions like usb_gadget_unregister_driver(). Meanwhile you can try following patch that returns checking of input parameters back and see if it helps. Best regards, Ruslan diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index fd73a3e..f1d375f 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -597,9 +597,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) } if (ret) { - list_del(>pending); - ret = 0; + struct usb_gadget_driver *tmp; + + list_for_each_entry(tmp, _driver_pending_list, pending) + if (tmp == driver) { + list_del(>pending); + ret = 0; + break; + } } + mutex_unlock(_lock); return ret; } -- 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 v7 0/4] usb/gadget: independent registration of gadgets and gadget drivers
Hi Marek, On Mon, Nov 23, 2015 at 10:56 AM, Marek Szyprowski <m.szyprow...@samsung.com> wrote: > Hello, > > This is a resurrection of the patches initially submitted by Ruslan > Bilovol in the following thread: https://lkml.org/lkml/2015/6/22/554 > > The changes since the original submission (v5) includes rebase onto > latest linux-next branch, simplification of the code requested by Alan > Stern and Felipe Balbi, removal of a patch, which deleted __init/__exit > attributes (this change has been already merged) and fixes of the > checkpatch issues. Thank you for handling it as I'm still to busy for continuing on this feature. Best regards, Ruslan > > This feature is urgently needed, because it is not longer possible to > use workaround to avoid deferred probe in UDC drivers due to > not-yet-probed i2c regulator drivers (for more information see > https://lkml.org/lkml/2015/10/30/374 ). > > This patchset has been successfully tested on Odroid XU3 boards with > DWC3 UDC driver being deferred by missing regulator drivers. > > Best regards > Marek Szyprowski > Samsung R Institute Poland > > > Patch summary: > > Ruslan Bilovol (4): > usb: gadget: bind UDC by name passed via usb_gadget_driver structure > usb: gadget: configfs: pass UDC name via usb_gadget_driver struct > usb: gadget: udc-core: remove unused usb_udc_attach_driver() > usb: gadget: udc-core: independent registration of gadgets and gadget > drivers > > drivers/usb/gadget/configfs.c | 29 +++--- > drivers/usb/gadget/udc/udc-core.c | 79 > ++- > include/linux/usb/gadget.h| 8 +++- > 3 files changed, 67 insertions(+), 49 deletions(-) > > -- > 1.9.2 > -- 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 v5 0/5] usb/gadget: independent registration of gadgets and gadget drivers
Hi Maxime, On Mon, Oct 19, 2015 at 11:11 AM, Maxime Ripard <maxime.rip...@free-electrons.com> wrote: > Hi, > > On Tue, Jun 23, 2015 at 01:01:09AM +0300, Ruslan Bilovol wrote: >> This patchset adds independent registration of gadgets >> and gadget drivers to udc-core. This is very useful for >> built-in modules into kernel case since it's possible >> situation that gadget driver is probing at a time >> when no gadgets are registered in udc-core. >> In this case instead of silently failing without >> of any attempt to recover, with independent registration >> of gadgets and gadget drivers there is no matter >> in which order gadgets and gadget drivers are >> probed/registered. >> >> This patch has side-effect on gadget drivers that had >> __init/__exit attributes on some paths like bind/unbind >> and (since bind/unbind may happen at any time) should >> not use them now. This is covered by forth patch >> > > Has there been any progress on these patches? They're fixing some real > issue that we're seeing, and it seems to both work quite well and not > generate a lot of pushback. This patch series has stack on review due to different views on checking input parameters of externally visible function. I see there is no any way to get these patches accepted other than skip checking validity of some input parameters as was pointed by Alan, although I disagree with it. I will post updated patch series later Best regards, Ruslan > > Thanks! > Maxime > > -- > Maxime Ripard, Free Electrons > Embedded Linux, Kernel and Android engineering > http://free-electrons.com -- 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 v5 2/5] usb: gadget: configfs: pass UDC name via usb_gadget_driver struct
Hi Krzysztof, On Tue, Jun 23, 2015 at 9:54 AM, Krzysztof Opasiak k.opas...@samsung.com wrote: Hello, On 06/23/2015 12:01 AM, Ruslan Bilovol wrote: Now when udc-core supports binding to specific UDC by passing its name via 'udc_name' member of usb_gadget_driver struct, switch to this generic approach. Tested-by: Maxime Ripard maxime.rip...@free-electrons.com Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/configfs.c | 27 ++- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index c42765b..efad021 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -54,7 +54,6 @@ struct gadget_info { struct list_head string_list; struct list_head available_func; - const char *udc_name; #ifdef CONFIG_USB_OTG struct usb_otg_descriptor otg; #endif @@ -230,21 +229,21 @@ static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi, static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page) { - return sprintf(page, %s\n, gi-udc_name ?: ); + return sprintf(page, %s\n, gi-composite.gadget_driver.udc_name ?: ); } static int unregister_gadget(struct gadget_info *gi) { int ret; - if (!gi-udc_name) + if (!gi-composite.gadget_driver.udc_name) return -ENODEV; ret = usb_gadget_unregister_driver(gi-composite.gadget_driver); if (ret) return ret; - kfree(gi-udc_name); - gi-udc_name = NULL; + kfree(gi-composite.gadget_driver.udc_name); + gi-composite.gadget_driver.udc_name = NULL; return 0; } @@ -267,14 +266,16 @@ static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi, if (ret) goto err; } else { - if (gi-udc_name) { + if (gi-composite.gadget_driver.udc_name) { You are using this very long if condition in a few places, maybe it would be more suitable to define a macro or inline function for this? Something like gadget_dev_bound() or gadget_dev_is_active() or some other more suitable name. Yes, it makes sense, since there are 11 places where this long access to udc_name is used. However, it is used not only in if conditions but also for changing udc_name, so need to add some getters/setters, something like #define gi_to_udc_name(gi) ((gi)-composite.gadget_driver.udc_name) #define gi_set_udc_name(gi,name) ((gi)-composite.gadget_driver.udc_name = (name)) Best regards, Ruslan -- 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 v5 5/5] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Hi Alan, On Tue, Jun 23, 2015 at 5:08 PM, Alan Stern st...@rowland.harvard.edu wrote: On Tue, 23 Jun 2015, Ruslan Bilovol wrote: Change behavior during registration of gadgets and gadget drivers in udc-core. Instead of previous approach when for successful probe of usb gadget driver at least one usb gadget should be already registered use another one where gadget drivers and gadgets can be registered in udc-core independently. Independent registration of gadgets and gadget drivers is useful for built-in into kernel gadget and gadget driver case - because it's possible that gadget is really probed only on late_init stage (due to deferred probe) whereas gadget driver's probe is silently failed on module_init stage due to no any UDC added. Also it is useful for modules case - now there is no difference what module to insert first: gadget module or gadget driver one. Tested-by: Maxime Ripard maxime.rip...@free-electrons.com Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com @@ -484,6 +507,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) break; } + if (ret) { + struct usb_gadget_driver *tmp; + + list_for_each_entry(tmp, gadget_driver_pending_list, pending) + if (tmp == driver) { + list_del(driver-pending); + ret = 0; + break; + } + } Weren't you going to replace this loop with a simple list_del()? IIRC, this is the third time I have asked you to make this change. I understand the improvement that replacing this loop with a list_del() may bring for us, but I disagree with doing it in this particular case. The reason is simple. The usb_gadget_unregister_driver() funciton is externally visible so we can get junk as input. Current implementation checks passed pointer and only after that does list_del(), or returns -EINVAL. Your variant will do list_del() unconditionally, that may cause a kernel crash or unexpected behavior in case of junk passed with *driver. The list_del_init() usage can't help here since there is no way to check that list_head structure is initialized with correct data or contains junk. There is no noticeable performance loss with current implementation,just because current use case is pretty simple: one gadget driver per one UDC, and usually there is only one UDC per machine (or rare cases with few UDCs), thus number of pending gadget drivers is relatively small. We can return back to this discussion if someone needs to register many gadget drivers, and want to improve performance, because there are few existing places (not created by me) in this file that uses same approach of walking through list of registered gadget drivers. As a bottom line, choosing between stability and little performance improvement, I prefer stability. Best regards, Ruslan -- 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 v5 4/5] usb: gadget: legacy: don't use __init/__exit attributes for bind/unbind path
In order to prepare to independent gadgets and gadget drivers registration in udc-core, some of the functions can't have __init/__exit attributes (almost only bind/unbind callbacks are affected) Tested-by: Maxime Ripard maxime.rip...@free-electrons.com Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/legacy/acm_ms.c | 6 +++--- drivers/usb/gadget/legacy/audio.c| 6 +++--- drivers/usb/gadget/legacy/cdc2.c | 6 +++--- drivers/usb/gadget/legacy/dbgp.c | 2 +- drivers/usb/gadget/legacy/ether.c| 8 drivers/usb/gadget/legacy/gmidi.c| 6 +++--- drivers/usb/gadget/legacy/hid.c | 6 +++--- drivers/usb/gadget/legacy/mass_storage.c | 4 ++-- drivers/usb/gadget/legacy/multi.c| 16 drivers/usb/gadget/legacy/ncm.c | 6 +++--- drivers/usb/gadget/legacy/nokia.c| 6 +++--- drivers/usb/gadget/legacy/printer.c | 6 +++--- drivers/usb/gadget/legacy/serial.c | 2 +- drivers/usb/gadget/legacy/webcam.c | 4 ++-- drivers/usb/gadget/legacy/zero.c | 2 +- 15 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index c30b7b5..3a48aab 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -121,7 +121,7 @@ static struct usb_function *f_msg; /* * We _always_ have both ACM and mass storage functions. */ -static int __init acm_ms_do_config(struct usb_configuration *c) +static int acm_ms_do_config(struct usb_configuration *c) { struct fsg_opts *opts; int status; @@ -174,7 +174,7 @@ static struct usb_configuration acm_ms_config_driver = { /*-*/ -static int __init acm_ms_bind(struct usb_composite_dev *cdev) +static int acm_ms_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev-gadget; struct fsg_opts *opts; @@ -249,7 +249,7 @@ fail_get_msg: return status; } -static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) +static int acm_ms_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_msg); usb_put_function_instance(fi_msg); diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index f46a395..ba95518 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -167,7 +167,7 @@ static const struct usb_descriptor_header *otg_desc[] = { /*-*/ -static int __init audio_do_config(struct usb_configuration *c) +static int audio_do_config(struct usb_configuration *c) { int status; @@ -216,7 +216,7 @@ static struct usb_configuration audio_config_driver = { /*-*/ -static int __init audio_bind(struct usb_composite_dev *cdev) +static int audio_bind(struct usb_composite_dev *cdev) { #ifndef CONFIG_GADGET_UAC1 struct f_uac2_opts *uac2_opts; @@ -276,7 +276,7 @@ fail: return status; } -static int __exit audio_unbind(struct usb_composite_dev *cdev) +static int audio_unbind(struct usb_composite_dev *cdev) { #ifdef CONFIG_GADGET_UAC1 if (!IS_ERR_OR_NULL(f_uac1)) diff --git a/drivers/usb/gadget/legacy/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c index 2e85d94..8d1985c 100644 --- a/drivers/usb/gadget/legacy/cdc2.c +++ b/drivers/usb/gadget/legacy/cdc2.c @@ -104,7 +104,7 @@ static struct usb_function_instance *fi_ecm; /* * We _always_ have both CDC ECM and CDC ACM functions. */ -static int __init cdc_do_config(struct usb_configuration *c) +static int cdc_do_config(struct usb_configuration *c) { int status; @@ -153,7 +153,7 @@ static struct usb_configuration cdc_config_driver = { /*-*/ -static int __init cdc_bind(struct usb_composite_dev *cdev) +static int cdc_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev-gadget; struct f_ecm_opts *ecm_opts; @@ -211,7 +211,7 @@ fail: return status; } -static int __exit cdc_unbind(struct usb_composite_dev *cdev) +static int cdc_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_acm); usb_put_function_instance(fi_serial); diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c index 633683a..7c42b01 100644 --- a/drivers/usb/gadget/legacy/dbgp.c +++ b/drivers/usb/gadget/legacy/dbgp.c @@ -284,7 +284,7 @@ fail_1: return -ENODEV; } -static int __init dbgp_bind(struct usb_gadget *gadget, +static int dbgp_bind(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { int err, stp; diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget
[PATCH v5 5/5] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Change behavior during registration of gadgets and gadget drivers in udc-core. Instead of previous approach when for successful probe of usb gadget driver at least one usb gadget should be already registered use another one where gadget drivers and gadgets can be registered in udc-core independently. Independent registration of gadgets and gadget drivers is useful for built-in into kernel gadget and gadget driver case - because it's possible that gadget is really probed only on late_init stage (due to deferred probe) whereas gadget driver's probe is silently failed on module_init stage due to no any UDC added. Also it is useful for modules case - now there is no difference what module to insert first: gadget module or gadget driver one. Tested-by: Maxime Ripard maxime.rip...@free-electrons.com Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 49 --- include/linux/usb/gadget.h| 2 ++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 441877d..5a764ea 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -51,8 +51,12 @@ struct usb_udc { static struct class *udc_class; static LIST_HEAD(udc_list); +static LIST_HEAD(gadget_driver_pending_list); static DEFINE_MUTEX(udc_lock); +static int udc_bind_to_driver(struct usb_udc *udc, + struct usb_gadget_driver *driver); + /* - */ #ifdef CONFIG_HAS_DMA @@ -264,6 +268,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)) { struct usb_udc *udc; + struct usb_gadget_driver *driver; int ret = -ENOMEM; udc = kzalloc(sizeof(*udc), GFP_KERNEL); @@ -311,6 +316,18 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); udc-vbus = true; + /* pick up one of pending gadget drivers */ + list_for_each_entry(driver, gadget_driver_pending_list, pending) { + if (!driver-udc_name || strcmp(driver-udc_name, + dev_name(udc-dev)) == 0) { + ret = udc_bind_to_driver(udc, driver); + if (ret) + goto err4; + list_del(driver-pending); + break; + } + } + mutex_unlock(udc_lock); return 0; @@ -382,9 +399,16 @@ void usb_del_gadget_udc(struct usb_gadget *gadget) list_del(udc-list); mutex_unlock(udc_lock); - if (udc-driver) + if (udc-driver) { + struct usb_gadget_driver *driver = udc-driver; + usb_gadget_remove_driver(udc); + mutex_lock(udc_lock); + list_add(driver-pending, gadget_driver_pending_list); + mutex_unlock(udc_lock); + } + kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); device_unregister(udc-dev); @@ -442,11 +466,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) if (!ret) break; } - if (ret) - ret = -ENODEV; - else if (udc-driver) - ret = -EBUSY; - else + if (!ret !udc-driver) goto found; } else { list_for_each_entry(udc, udc_list, list) { @@ -456,9 +476,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) } } - pr_debug(couldn't find an available UDC\n); + list_add_tail(driver-pending, gadget_driver_pending_list); + pr_info(udc-core: couldn't find an available UDC + - added [%s] to list of pending drivers\n, + driver-function); mutex_unlock(udc_lock); - return ret; + return 0; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(udc_lock); @@ -484,6 +507,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) break; } + if (ret) { + struct usb_gadget_driver *tmp; + + list_for_each_entry(tmp, gadget_driver_pending_list, pending) + if (tmp == driver) { + list_del(driver-pending); + ret = 0; + break; + } + } mutex_unlock(udc_lock); return ret; } diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 5482d13..9c6fe22
[PATCH v5 3/5] usb: gadget: udc-core: remove unused usb_udc_attach_driver()
Now when last user of usb_udc_attach_driver() is switched to passing UDC name via usb_gadget_driver struct, it's safe to remove this function Tested-by: Maxime Ripard maxime.rip...@free-electrons.com Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 26 -- include/linux/usb/gadget.h| 2 -- 2 files changed, 28 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index b431129..441877d 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -427,32 +427,6 @@ err1: return ret; } -int usb_udc_attach_driver(const char *name, struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - mutex_lock(udc_lock); - list_for_each_entry(udc, udc_list, list) { - ret = strcmp(name, dev_name(udc-dev)); - if (!ret) - break; - } - if (ret) { - ret = -ENODEV; - goto out; - } - if (udc-driver) { - ret = -EBUSY; - goto out; - } - ret = udc_bind_to_driver(udc, driver); -out: - mutex_unlock(udc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(usb_udc_attach_driver); - int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 8bba379..5482d13 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -933,8 +933,6 @@ extern int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)); extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget); extern void usb_del_gadget_udc(struct usb_gadget *gadget); -extern int usb_udc_attach_driver(const char *name, - struct usb_gadget_driver *driver); /*-*/ -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in
[PATCH v5 2/5] usb: gadget: configfs: pass UDC name via usb_gadget_driver struct
Now when udc-core supports binding to specific UDC by passing its name via 'udc_name' member of usb_gadget_driver struct, switch to this generic approach. Tested-by: Maxime Ripard maxime.rip...@free-electrons.com Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/configfs.c | 27 ++- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index c42765b..efad021 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -54,7 +54,6 @@ struct gadget_info { struct list_head string_list; struct list_head available_func; - const char *udc_name; #ifdef CONFIG_USB_OTG struct usb_otg_descriptor otg; #endif @@ -230,21 +229,21 @@ static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi, static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page) { - return sprintf(page, %s\n, gi-udc_name ?: ); + return sprintf(page, %s\n, gi-composite.gadget_driver.udc_name ?: ); } static int unregister_gadget(struct gadget_info *gi) { int ret; - if (!gi-udc_name) + if (!gi-composite.gadget_driver.udc_name) return -ENODEV; ret = usb_gadget_unregister_driver(gi-composite.gadget_driver); if (ret) return ret; - kfree(gi-udc_name); - gi-udc_name = NULL; + kfree(gi-composite.gadget_driver.udc_name); + gi-composite.gadget_driver.udc_name = NULL; return 0; } @@ -267,14 +266,16 @@ static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi, if (ret) goto err; } else { - if (gi-udc_name) { + if (gi-composite.gadget_driver.udc_name) { ret = -EBUSY; goto err; } - ret = usb_udc_attach_driver(name, gi-composite.gadget_driver); - if (ret) + gi-composite.gadget_driver.udc_name = name; + ret = usb_gadget_probe_driver(gi-composite.gadget_driver); + if (ret) { + gi-composite.gadget_driver.udc_name = NULL; goto err; - gi-udc_name = name; + } } mutex_unlock(gi-lock); return len; @@ -438,9 +439,9 @@ static int config_usb_cfg_unlink( * remove the function. */ mutex_lock(gi-lock); - if (gi-udc_name) + if (gi-composite.gadget_driver.udc_name) unregister_gadget(gi); - WARN_ON(gi-udc_name); + WARN_ON(gi-composite.gadget_driver.udc_name); list_for_each_entry(f, cfg-func_list, list) { if (f-fi == fi) { @@ -917,10 +918,10 @@ static int os_desc_unlink(struct config_item *os_desc_ci, struct usb_composite_dev *cdev = gi-cdev; mutex_lock(gi-lock); - if (gi-udc_name) + if (gi-composite.gadget_driver.udc_name) unregister_gadget(gi); cdev-os_desc_config = NULL; - WARN_ON(gi-udc_name); + WARN_ON(gi-composite.gadget_driver.udc_name); mutex_unlock(gi-lock); return 0; } -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in
[PATCH v5 0/5] usb/gadget: independent registration of gadgets and gadget drivers
This patchset adds independent registration of gadgets and gadget drivers to udc-core. This is very useful for built-in modules into kernel case since it's possible situation that gadget driver is probing at a time when no gadgets are registered in udc-core. In this case instead of silently failing without of any attempt to recover, with independent registration of gadgets and gadget drivers there is no matter in which order gadgets and gadget drivers are probed/registered. This patch has side-effect on gadget drivers that had __init/__exit attributes on some paths like bind/unbind and (since bind/unbind may happen at any time) should not use them now. This is covered by forth patch = v5: - this set of patches (that I already forgot about) has been successfully tested by Maxime Ripard, who sent me confirmation via personal email, so his Tested-by tag is added to the patches - rebased onto latest 'next' branch of Felipe Balbi's tree v4: - misc fixes - addressed Alan's and Sergei's comments - rebased onto latest 'next' branch of Felipe Balbi's tree v3: - addressed Alan's comments - now UDC name and pending gadget drivers list is a part of struct usb_gadget_driver. - removed usb_udc_attach_driver() function that became unused and not needed now v2: - changed first patch to have only deferred probe part (because Gadget Bus seems to be better variant when some more complicated behavior will be required) - rebased to latest 'next' branch of Felipe Balbi's tree Ruslan Bilovol (5): usb: gadget: bind UDC by name passed via usb_gadget_driver structure usb: gadget: configfs: pass UDC name via usb_gadget_driver struct usb: gadget: udc-core: remove unused usb_udc_attach_driver() usb: gadget: legacy: don't use __init/__exit attributes for bind/unbind path usb: gadget: udc-core: independent registration of gadgets and gadget drivers drivers/usb/gadget/configfs.c| 27 +- drivers/usb/gadget/legacy/acm_ms.c | 6 +-- drivers/usb/gadget/legacy/audio.c| 6 +-- drivers/usb/gadget/legacy/cdc2.c | 6 +-- drivers/usb/gadget/legacy/dbgp.c | 2 +- drivers/usb/gadget/legacy/ether.c| 8 +-- drivers/usb/gadget/legacy/gmidi.c| 6 +-- drivers/usb/gadget/legacy/hid.c | 6 +-- drivers/usb/gadget/legacy/mass_storage.c | 4 +- drivers/usb/gadget/legacy/multi.c| 16 +++--- drivers/usb/gadget/legacy/ncm.c | 6 +-- drivers/usb/gadget/legacy/nokia.c| 6 +-- drivers/usb/gadget/legacy/printer.c | 6 +-- drivers/usb/gadget/legacy/serial.c | 2 +- drivers/usb/gadget/legacy/webcam.c | 4 +- drivers/usb/gadget/legacy/zero.c | 2 +- drivers/usb/gadget/udc/udc-core.c| 87 include/linux/usb/gadget.h | 8 ++- 18 files changed, 117 insertions(+), 91 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in
[PATCH v5 1/5] usb: gadget: bind UDC by name passed via usb_gadget_driver structure
Introduce new 'udc_name' member to usb_gadget_driver structure. The 'udc_name' is a name of UDC that usb_gadget_driver should be bound to. If udc_name is NULL, it will be bound to any available UDC. Tested-by: Maxime Ripard maxime.rip...@free-electrons.com Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 24 +++- include/linux/usb/gadget.h| 4 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index d69c355..b431129 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -456,21 +456,35 @@ EXPORT_SYMBOL_GPL(usb_udc_attach_driver); int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; - int ret; + int ret = -ENODEV; if (!driver || !driver-bind || !driver-setup) return -EINVAL; mutex_lock(udc_lock); - list_for_each_entry(udc, udc_list, list) { - /* For now we take the first one */ - if (!udc-driver) + if (driver-udc_name) { + list_for_each_entry(udc, udc_list, list) { + ret = strcmp(driver-udc_name, dev_name(udc-dev)); + if (!ret) + break; + } + if (ret) + ret = -ENODEV; + else if (udc-driver) + ret = -EBUSY; + else goto found; + } else { + list_for_each_entry(udc, udc_list, list) { + /* For now we take the first one */ + if (!udc-driver) + goto found; + } } pr_debug(couldn't find an available UDC\n); mutex_unlock(udc_lock); - return -ENODEV; + return ret; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(udc_lock); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 4f3dfb7..8bba379 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -824,6 +824,8 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) * @reset: Invoked on USB bus reset. It is mandatory for all gadget drivers * and should be called in_interrupt. * @driver: Driver model state for this driver. + * @udc_name: A name of UDC this driver should be bound to. If udc_name is NULL, + * this driver will be bound to any available UDC. * * Devices are disabled till a gadget driver successfully bind()s, which * means the driver will handle setup() requests needed to enumerate (and @@ -884,6 +886,8 @@ struct usb_gadget_driver { /* FIXME support safe rmmod */ struct device_driverdriver; + + char*udc_name; }; -- 1.9.1 -- To unsubscribe from this list: send the line unsubscribe linux-usb in
Re: [PATCH v4 5/5] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
HI Alan, On Fri, Mar 13, 2015 at 4:39 PM, Alan Stern st...@rowland.harvard.edu wrote: On Thu, 12 Mar 2015, Ruslan Bilovol wrote: Change behavior during registration of gadgets and gadget drivers in udc-core. Instead of previous approach when for successful probe of usb gadget driver at least one usb gadget should be already registered use another one where gadget drivers and gadgets can be registered in udc-core independently. Independent registration of gadgets and gadget drivers is useful for built-in into kernel gadget and gadget driver case - because it's possible that gadget is really probed only on late_init stage (due to deferred probe) whereas gadget driver's probe is silently failed on module_init stage due to no any UDC added. Also it is useful for modules case - now there is no difference what module to insert first: gadget module or gadget driver one. @@ -366,9 +383,16 @@ found: list_del(udc-list); mutex_unlock(udc_lock); - if (udc-driver) + if (udc-driver) { + struct usb_gadget_driver *driver = udc-driver; + usb_gadget_remove_driver(udc); + mutex_lock(udc_lock); + list_add(driver-pending, gadget_driver_pending_list); + mutex_unlock(udc_lock); + } I'm not sure this is a good idea. Gadget drivers probably don't expect to be bound again after they are unbound. This already has been discussed some time ago: https://lkml.org/lkml/2015/2/9/497 The bottom line was - such gadget drivers are buggy and need to be fixed since there is no known restrictions in binding gadget drivers to UDC multiple times Besides, when would this gadget driver get bound to a UDC? Not until the next UDC is added -- even if there already are some unbound UDCs. Currently this gadget driver will get bound to a UDC only when next UDC is added. It seems there is no users of this feature, so I didn't add full implementation of this (that I had in version #1 if this patch: https://lkml.org/lkml/2015/1/28/1079 ) @@ -468,6 +491,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) break; } + if (ret) { + struct usb_gadget_driver *tmp; + + list_for_each_entry(tmp, gadget_driver_pending_list, pending) + if (tmp == driver) { + list_del(driver-pending); + ret = 0; + break; + } + } You could avoid this loop and simply do list_del(driver-pending), if you made sure driver-pending was initialized. It would be good to avoid this loop but the question is how to make sure that driver-pending is not only initialized (prev and next are not NULL), but also contains valid data? Best regards, Ruslan -- 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 v4 0/5] usb/gadget: independent registration of gadgets and gadget drivers
This patchset adds independent registration of gadgets and gadget drivers to udc-core. This is very useful for built-in modules into kernel case since it's possible situation that gadget driver is probing at a time when no gadgets are registered in udc-core. In this case instead of silently failing without of any attempt to recover, with independent registration of gadgets and gadget drivers there is no matter in which order gadgets and gadget drivers are probed/registered. This patch has side-effect on gadget drivers that had __init/__exit attributes on some paths like bind/unbind and (since bind/unbind may happen at any time) should not use them now. This is covered by forth patch = v4: - misc fixes - addressed Alan's and Sergei's comments - rebased onto latest 'next' branch of Felipe Balbi's tree v3: - addressed Alan's comments - now UDC name and pending gadget drivers list is a part of struct usb_gadget_driver. - removed usb_udc_attach_driver() function that became unused and not needed now v2: - changed first patch to have only deferred probe part (because Gadget Bus seems to be better variant when some more complicated behavior will be required) - rebased to latest 'next' branch of Felipe Balbi's tree Ruslan Bilovol (5): usb: gadget: bind UDC by name passed via usb_gadget_driver structure usb: gadget: configfs: pass UDC name via usb_gadget_driver struct usb: gadget: udc-core: remove unused usb_udc_attach_driver() usb: gadget: legacy: don't use __init/__exit attributes for bind/unbind path usb: gadget: udc-core: independent registration of gadgets and gadget drivers drivers/usb/gadget/configfs.c| 27 +- drivers/usb/gadget/legacy/acm_ms.c | 6 +-- drivers/usb/gadget/legacy/audio.c| 6 +-- drivers/usb/gadget/legacy/cdc2.c | 6 +-- drivers/usb/gadget/legacy/dbgp.c | 2 +- drivers/usb/gadget/legacy/ether.c| 8 +-- drivers/usb/gadget/legacy/gmidi.c| 6 +-- drivers/usb/gadget/legacy/hid.c | 6 +-- drivers/usb/gadget/legacy/mass_storage.c | 4 +- drivers/usb/gadget/legacy/multi.c| 16 +++--- drivers/usb/gadget/legacy/ncm.c | 6 +-- drivers/usb/gadget/legacy/nokia.c| 6 +-- drivers/usb/gadget/legacy/printer.c | 6 +-- drivers/usb/gadget/legacy/serial.c | 2 +- drivers/usb/gadget/legacy/webcam.c | 4 +- drivers/usb/gadget/legacy/zero.c | 2 +- drivers/usb/gadget/udc/udc-core.c| 87 include/linux/usb/gadget.h | 8 ++- 18 files changed, 117 insertions(+), 91 deletions(-) -- 1.9.1 -- 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 v4 3/5] usb: gadget: udc-core: remove unused usb_udc_attach_driver()
Now when last user of usb_udc_attach_driver() is switched to passing UDC name via usb_gadget_driver struct, it's safe to remove this function Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 26 -- include/linux/usb/gadget.h| 2 -- 2 files changed, 28 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index da738ee..3165d48 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -411,32 +411,6 @@ err1: return ret; } -int usb_udc_attach_driver(const char *name, struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - mutex_lock(udc_lock); - list_for_each_entry(udc, udc_list, list) { - ret = strcmp(name, dev_name(udc-dev)); - if (!ret) - break; - } - if (ret) { - ret = -ENODEV; - goto out; - } - if (udc-driver) { - ret = -EBUSY; - goto out; - } - ret = udc_bind_to_driver(udc, driver); -out: - mutex_unlock(udc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(usb_udc_attach_driver); - int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 6d26657..b584ed2 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -930,8 +930,6 @@ extern int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)); extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget); extern void usb_del_gadget_udc(struct usb_gadget *gadget); -extern int usb_udc_attach_driver(const char *name, - struct usb_gadget_driver *driver); /*-*/ -- 1.9.1 -- 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 v4 5/5] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Change behavior during registration of gadgets and gadget drivers in udc-core. Instead of previous approach when for successful probe of usb gadget driver at least one usb gadget should be already registered use another one where gadget drivers and gadgets can be registered in udc-core independently. Independent registration of gadgets and gadget drivers is useful for built-in into kernel gadget and gadget driver case - because it's possible that gadget is really probed only on late_init stage (due to deferred probe) whereas gadget driver's probe is silently failed on module_init stage due to no any UDC added. Also it is useful for modules case - now there is no difference what module to insert first: gadget module or gadget driver one. Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 49 --- include/linux/usb/gadget.h| 2 ++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 3165d48..53571dd 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -48,8 +48,12 @@ struct usb_udc { static struct class *udc_class; static LIST_HEAD(udc_list); +static LIST_HEAD(gadget_driver_pending_list); static DEFINE_MUTEX(udc_lock); +static int udc_bind_to_driver(struct usb_udc *udc, + struct usb_gadget_driver *driver); + /* - */ #ifdef CONFIG_HAS_DMA @@ -243,6 +247,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)) { struct usb_udc *udc; + struct usb_gadget_driver *driver; int ret = -ENOMEM; udc = kzalloc(sizeof(*udc), GFP_KERNEL); @@ -288,6 +293,18 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); + /* pick up one of pending gadget drivers */ + list_for_each_entry(driver, gadget_driver_pending_list, pending) { + if (!driver-udc_name || strcmp(driver-udc_name, + dev_name(udc-dev)) == 0) { + ret = udc_bind_to_driver(udc, driver); + if (ret) + goto err4; + list_del(driver-pending); + break; + } + } + mutex_unlock(udc_lock); return 0; @@ -366,9 +383,16 @@ found: list_del(udc-list); mutex_unlock(udc_lock); - if (udc-driver) + if (udc-driver) { + struct usb_gadget_driver *driver = udc-driver; + usb_gadget_remove_driver(udc); + mutex_lock(udc_lock); + list_add(driver-pending, gadget_driver_pending_list); + mutex_unlock(udc_lock); + } + kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); device_unregister(udc-dev); @@ -426,11 +450,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) if (!ret) break; } - if (ret) - ret = -ENODEV; - else if (udc-driver) - ret = -EBUSY; - else + if (!ret !udc-driver) goto found; } else { list_for_each_entry(udc, udc_list, list) { @@ -440,9 +460,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) } } - pr_debug(couldn't find an available UDC\n); + list_add_tail(driver-pending, gadget_driver_pending_list); + pr_info(udc-core: couldn't find an available UDC + - added [%s] to list of pending drivers\n, + driver-function); mutex_unlock(udc_lock); - return ret; + return 0; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(udc_lock); @@ -468,6 +491,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) break; } + if (ret) { + struct usb_gadget_driver *tmp; + + list_for_each_entry(tmp, gadget_driver_pending_list, pending) + if (tmp == driver) { + list_del(driver-pending); + ret = 0; + break; + } + } mutex_unlock(udc_lock); return ret; } diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index b584ed2..ccf872f 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -823,6 +823,7 @@ static inline int
[PATCH v4 1/5] usb: gadget: bind UDC by name passed via usb_gadget_driver structure
Introduce new 'udc_name' member to usb_gadget_driver structure. The 'udc_name' is a name of UDC that usb_gadget_driver should be bound to. If udc_name is NULL, it will be bound to any available UDC. Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 24 +++- include/linux/usb/gadget.h| 4 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 5a81cb0..da738ee 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -440,21 +440,35 @@ EXPORT_SYMBOL_GPL(usb_udc_attach_driver); int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; - int ret; + int ret = -ENODEV; if (!driver || !driver-bind || !driver-setup) return -EINVAL; mutex_lock(udc_lock); - list_for_each_entry(udc, udc_list, list) { - /* For now we take the first one */ - if (!udc-driver) + if (driver-udc_name) { + list_for_each_entry(udc, udc_list, list) { + ret = strcmp(driver-udc_name, dev_name(udc-dev)); + if (!ret) + break; + } + if (ret) + ret = -ENODEV; + else if (udc-driver) + ret = -EBUSY; + else goto found; + } else { + list_for_each_entry(udc, udc_list, list) { + /* For now we take the first one */ + if (!udc-driver) + goto found; + } } pr_debug(couldn't find an available UDC\n); mutex_unlock(udc_lock); - return -ENODEV; + return ret; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(udc_lock); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 02476b3..6d26657 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -821,6 +821,8 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) * @reset: Invoked on USB bus reset. It is mandatory for all gadget drivers * and should be called in_interrupt. * @driver: Driver model state for this driver. + * @udc_name: A name of UDC this driver should be bound to. If udc_name is NULL, + * this driver will be bound to any available UDC. * * Devices are disabled till a gadget driver successfully bind()s, which * means the driver will handle setup() requests needed to enumerate (and @@ -881,6 +883,8 @@ struct usb_gadget_driver { /* FIXME support safe rmmod */ struct device_driverdriver; + + char*udc_name; }; -- 1.9.1 -- 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 v4 2/5] usb: gadget: configfs: pass UDC name via usb_gadget_driver struct
Now when udc-core supports binding to specific UDC by passing its name via 'udc_name' member of usb_gadget_driver struct, switch to this generic approach. Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/configfs.c | 27 ++- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index c42765b..efad021 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -54,7 +54,6 @@ struct gadget_info { struct list_head string_list; struct list_head available_func; - const char *udc_name; #ifdef CONFIG_USB_OTG struct usb_otg_descriptor otg; #endif @@ -230,21 +229,21 @@ static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi, static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page) { - return sprintf(page, %s\n, gi-udc_name ?: ); + return sprintf(page, %s\n, gi-composite.gadget_driver.udc_name ?: ); } static int unregister_gadget(struct gadget_info *gi) { int ret; - if (!gi-udc_name) + if (!gi-composite.gadget_driver.udc_name) return -ENODEV; ret = usb_gadget_unregister_driver(gi-composite.gadget_driver); if (ret) return ret; - kfree(gi-udc_name); - gi-udc_name = NULL; + kfree(gi-composite.gadget_driver.udc_name); + gi-composite.gadget_driver.udc_name = NULL; return 0; } @@ -267,14 +266,16 @@ static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi, if (ret) goto err; } else { - if (gi-udc_name) { + if (gi-composite.gadget_driver.udc_name) { ret = -EBUSY; goto err; } - ret = usb_udc_attach_driver(name, gi-composite.gadget_driver); - if (ret) + gi-composite.gadget_driver.udc_name = name; + ret = usb_gadget_probe_driver(gi-composite.gadget_driver); + if (ret) { + gi-composite.gadget_driver.udc_name = NULL; goto err; - gi-udc_name = name; + } } mutex_unlock(gi-lock); return len; @@ -438,9 +439,9 @@ static int config_usb_cfg_unlink( * remove the function. */ mutex_lock(gi-lock); - if (gi-udc_name) + if (gi-composite.gadget_driver.udc_name) unregister_gadget(gi); - WARN_ON(gi-udc_name); + WARN_ON(gi-composite.gadget_driver.udc_name); list_for_each_entry(f, cfg-func_list, list) { if (f-fi == fi) { @@ -917,10 +918,10 @@ static int os_desc_unlink(struct config_item *os_desc_ci, struct usb_composite_dev *cdev = gi-cdev; mutex_lock(gi-lock); - if (gi-udc_name) + if (gi-composite.gadget_driver.udc_name) unregister_gadget(gi); cdev-os_desc_config = NULL; - WARN_ON(gi-udc_name); + WARN_ON(gi-composite.gadget_driver.udc_name); mutex_unlock(gi-lock); return 0; } -- 1.9.1 -- 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 v4 4/5] usb: gadget: legacy: don't use __init/__exit attributes for bind/unbind path
In order to prepare to independent gadgets and gadget drivers registration in udc-core, some of the functions can't have __init/__exit attributes (almost only bind/unbind callbacks are affected) Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/legacy/acm_ms.c | 6 +++--- drivers/usb/gadget/legacy/audio.c| 6 +++--- drivers/usb/gadget/legacy/cdc2.c | 6 +++--- drivers/usb/gadget/legacy/dbgp.c | 2 +- drivers/usb/gadget/legacy/ether.c| 8 drivers/usb/gadget/legacy/gmidi.c| 6 +++--- drivers/usb/gadget/legacy/hid.c | 6 +++--- drivers/usb/gadget/legacy/mass_storage.c | 4 ++-- drivers/usb/gadget/legacy/multi.c| 16 drivers/usb/gadget/legacy/ncm.c | 6 +++--- drivers/usb/gadget/legacy/nokia.c| 6 +++--- drivers/usb/gadget/legacy/printer.c | 6 +++--- drivers/usb/gadget/legacy/serial.c | 2 +- drivers/usb/gadget/legacy/webcam.c | 4 ++-- drivers/usb/gadget/legacy/zero.c | 2 +- 15 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index c30b7b5..3a48aab 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -121,7 +121,7 @@ static struct usb_function *f_msg; /* * We _always_ have both ACM and mass storage functions. */ -static int __init acm_ms_do_config(struct usb_configuration *c) +static int acm_ms_do_config(struct usb_configuration *c) { struct fsg_opts *opts; int status; @@ -174,7 +174,7 @@ static struct usb_configuration acm_ms_config_driver = { /*-*/ -static int __init acm_ms_bind(struct usb_composite_dev *cdev) +static int acm_ms_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev-gadget; struct fsg_opts *opts; @@ -249,7 +249,7 @@ fail_get_msg: return status; } -static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) +static int acm_ms_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_msg); usb_put_function_instance(fi_msg); diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index f46a395..ba95518 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -167,7 +167,7 @@ static const struct usb_descriptor_header *otg_desc[] = { /*-*/ -static int __init audio_do_config(struct usb_configuration *c) +static int audio_do_config(struct usb_configuration *c) { int status; @@ -216,7 +216,7 @@ static struct usb_configuration audio_config_driver = { /*-*/ -static int __init audio_bind(struct usb_composite_dev *cdev) +static int audio_bind(struct usb_composite_dev *cdev) { #ifndef CONFIG_GADGET_UAC1 struct f_uac2_opts *uac2_opts; @@ -276,7 +276,7 @@ fail: return status; } -static int __exit audio_unbind(struct usb_composite_dev *cdev) +static int audio_unbind(struct usb_composite_dev *cdev) { #ifdef CONFIG_GADGET_UAC1 if (!IS_ERR_OR_NULL(f_uac1)) diff --git a/drivers/usb/gadget/legacy/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c index 2e85d94..8d1985c 100644 --- a/drivers/usb/gadget/legacy/cdc2.c +++ b/drivers/usb/gadget/legacy/cdc2.c @@ -104,7 +104,7 @@ static struct usb_function_instance *fi_ecm; /* * We _always_ have both CDC ECM and CDC ACM functions. */ -static int __init cdc_do_config(struct usb_configuration *c) +static int cdc_do_config(struct usb_configuration *c) { int status; @@ -153,7 +153,7 @@ static struct usb_configuration cdc_config_driver = { /*-*/ -static int __init cdc_bind(struct usb_composite_dev *cdev) +static int cdc_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev-gadget; struct f_ecm_opts *ecm_opts; @@ -211,7 +211,7 @@ fail: return status; } -static int __exit cdc_unbind(struct usb_composite_dev *cdev) +static int cdc_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_acm); usb_put_function_instance(fi_serial); diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c index 633683a..7c42b01 100644 --- a/drivers/usb/gadget/legacy/dbgp.c +++ b/drivers/usb/gadget/legacy/dbgp.c @@ -284,7 +284,7 @@ fail_1: return -ENODEV; } -static int __init dbgp_bind(struct usb_gadget *gadget, +static int dbgp_bind(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { int err, stp; diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget/legacy/ether.c index c5fdc61..4283969 100644 --- a/drivers/usb
Re: [PATCHv3 5/5] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Hi Alan, On Tue, Feb 17, 2015 at 11:51 PM, Alan Stern st...@rowland.harvard.edu wrote: On Tue, 17 Feb 2015, Ruslan Bilovol wrote: Change behavior during registration of gadgets and gadget drivers in udc-core. Instead of previous approach when for successful probe of usb gadget driver at least one usb gadget should be already registered use another one where gadget drivers and gadgets can be registered in udc-core independently. Independent registration of gadgets and gadget drivers is useful for built-in into kernel gadget and gadget driver case - because it's possible that gadget is really probed only on late_init stage (due to deferred probe) whereas gadget driver's probe is silently failed on module_init stage due to no any UDC added. Also it is useful for modules case - now there is no difference what module to insert first: gadget module or gadget driver one. Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 51 ++- include/linux/usb/gadget.h| 2 ++ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index a960f3f..9e82497 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -48,8 +48,11 @@ struct usb_udc { static struct class *udc_class; static LIST_HEAD(udc_list); +static LIST_HEAD(gadget_driver_pending_list); static DEFINE_MUTEX(udc_lock); +static int udc_bind_to_driver(struct usb_udc *udc, + struct usb_gadget_driver *driver); Strange indentation, not at all like the other continuation lines in this source file. Also, there should be a blank line here, as in the original file. Will fix it /* - */ #ifdef CONFIG_HAS_DMA @@ -243,6 +246,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)) { struct usb_udc *udc; + struct usb_gadget_driver *pgadget; Don't call it pgadget. None of the other pointer variables in this file have an extra p added to the beginnings of their names. It seems this name is confusing (it is intended to have pending gadget meaning). Will change it in next patch version int ret = -ENOMEM; udc = kzalloc(sizeof(*udc), GFP_KERNEL); @@ -288,6 +292,18 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); + /* pick up one of pending gadget drivers */ + list_for_each_entry(pgadget, gadget_driver_pending_list, pending) { + if (!pgadget-udc_name || strcmp(pgadget-udc_name, + dev_name(udc-dev)) == 0) { + ret = udc_bind_to_driver(udc, pgadget); Are you sure it's safe to call this routine while holding the udc_lock mutex? Yes, it's safe here, in the only place where it was used before this routine is also called while holding the udc_lock mutex (see usb_gadget_probe_driver) + if (ret) + goto err4; + list_del(pgadget-pending); Use list_del_init(). + break; + } + } + mutex_unlock(udc_lock); return 0; @@ -364,10 +380,11 @@ found: dev_vdbg(gadget-dev.parent, unregistering gadget\n); list_del(udc-list); - mutex_unlock(udc_lock); - - if (udc-driver) + if (udc-driver) { + list_add(udc-driver-pending, gadget_driver_pending_list); usb_gadget_remove_driver(udc); Are you sure it's safe to call this routine while holding the udc_lock mutex? Should not be any issue here but it's possible to prevent this, will do it in next patch version + } + mutex_unlock(udc_lock); kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); @@ -426,24 +443,26 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) if (!ret) break; } - if (ret) - ret = -ENODEV; - else if (udc-driver) - ret = -EBUSY; - else + if (!ret udc-driver) { + mutex_unlock(udc_lock); + return -EBUSY; This is a judgement call. It might be better to return 0 and add the gadget driver to the pending list. Yes, that makes sense, will change it + } else if (!ret) { goto found; + } } else { list_for_each_entry(udc, udc_list, list) { /* For now we take the first one */ if (!udc-driver
Re: [PATCHv3 1/5] usb: gadget: bind UDC by name passed via usb_gadget_driver structure
Hi Sergei, On Wed, Feb 18, 2015 at 2:05 PM, Sergei Shtylyov sergei.shtyl...@cogentembedded.com wrote: Hello. On 2/18/2015 12:17 AM, Ruslan Bilovol wrote: Introduce new 'udc_name' member to usb_gadget_driver structure. The 'udc_name' is a name of UDC that usb_gadget_driver should be bound to. If udc_name is NULL, it will be bound to any available UDC. Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 25 - include/linux/usb/gadget.h| 4 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 5a81cb0..e1079e08 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -440,21 +440,36 @@ EXPORT_SYMBOL_GPL(usb_udc_attach_driver); int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; - int ret; + int ret = -ENODEV; if (!driver || !driver-bind || !driver-setup) return -EINVAL; mutex_lock(udc_lock); - list_for_each_entry(udc, udc_list, list) { - /* For now we take the first one */ - if (!udc-driver) + if (driver-udc_name) { + list_for_each_entry(udc, udc_list, list) { + ret = strcmp(driver-udc_name, dev_name(udc-dev)); + if (!ret) + break; + } + if (ret) + ret = -ENODEV; + else if (udc-driver) + ret = -EBUSY; + else goto found; + } else { + list_for_each_entry(udc, udc_list, list) { + /* For now we take the first one */ + if (!udc-driver) + goto found; + } + ret = -ENODEV; Already assigned the same value by the initializer. Thanks for pointing to this, will be fixed in next patch version } pr_debug(couldn't find an available UDC\n); mutex_unlock(udc_lock); - return -ENODEV; + return ret; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(udc_lock); [...] WBR, Sergei Best regards, Ruslan -- 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] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Hi Andrzej, On Mon, Feb 16, 2015 at 10:07 AM, Andrzej Pietrasiewicz andrze...@samsung.com wrote: W dniu 15.02.2015 o 23:43, Ruslan Bilovol pisze: snip In my opinion all things which you have described are working out-of-box when you use configfs interface. It's mostly ready so you may create equivalent of most legacy gadgets (apart from printer and tcm) and just bind from one udc to another whenever you want. It's because legacy gadgets are easy to use and usually don't need any userspace-side configuration. Are there any plans to remove legacy drivers in the future? I'm not going to express strong opinions here, but their name implies that this can happen, some time in the future. And I also think it will not happen before the userspace part (libusbg, gt, gadgetd etc) is mature enough. My personal opinion in that matter is that it will take at least a couple of years to remove legacy gadgets entirely. OK, so it looks like there is a sense even to add new gadget/functions with legacy support Thanks, Ruslan AP -- 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
[PATCHv3 0/5] usb/gadget: independent registration of gadgets and gadget drivers
This patchset adds independent registration of gadgets and gadget drivers to udc-core. This is very useful for built-in modules into kernel case since it's possible situation that gadget driver is probing at a time when no gadgets are registered in udc-core. In this case instead of silently failing without of any attempt to recover, with independent registration of gadgets and gadget drivers there is no matter in which order gadgets and gadget drivers are probed/registered. This patch has side-effect on gadget drivers that had __init/__exit attributes on some paths like bind/unbind and (since bind/unbind may happen at any time) should not use them now. This is covered by forth patch = v3: - addressed Alan's comments - now UDC name and pending gadget drivers list is a part of struct usb_gadget_driver. - removed usb_udc_attach_driver() function that became unused and not needed now v2: - changed first patch to have only deferred probe part (because Gadget Bus seems to be better variant when some more complicated behavior will be required) - rebased to latest 'next' branch of Felipe Balbi's tree Ruslan Bilovol (5): usb: gadget: bind UDC by name passed via usb_gadget_driver structure usb: gadge: configfs: pass UDC name via usb_gadget_driver struct usb: gadget: udc-core: remove unused usb_udc_attach_driver() usb: gadget: legacy: don't use __init/__exit attributes for bind/unbind path usb: gadget: udc-core: independent registration of gadgets and gadget drivers drivers/usb/gadget/configfs.c| 27 +- drivers/usb/gadget/legacy/acm_ms.c | 6 +-- drivers/usb/gadget/legacy/audio.c| 6 +-- drivers/usb/gadget/legacy/cdc2.c | 6 +-- drivers/usb/gadget/legacy/dbgp.c | 2 +- drivers/usb/gadget/legacy/ether.c| 8 +-- drivers/usb/gadget/legacy/gmidi.c| 6 +-- drivers/usb/gadget/legacy/hid.c | 6 +-- drivers/usb/gadget/legacy/mass_storage.c | 4 +- drivers/usb/gadget/legacy/multi.c| 16 +++--- drivers/usb/gadget/legacy/ncm.c | 6 +-- drivers/usb/gadget/legacy/nokia.c| 6 +-- drivers/usb/gadget/legacy/printer.c | 6 +-- drivers/usb/gadget/legacy/serial.c | 2 +- drivers/usb/gadget/legacy/webcam.c | 4 +- drivers/usb/gadget/legacy/zero.c | 2 +- drivers/usb/gadget/udc/udc-core.c| 88 +++- include/linux/usb/gadget.h | 8 ++- 18 files changed, 116 insertions(+), 93 deletions(-) -- 1.9.1 -- 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
[PATCHv3 2/5] usb: gadge: configfs: pass UDC name via usb_gadget_driver struct
Now when udc-core supports binding to specific UDC by passing its name via 'udc_name' member of usb_gadget_driver struct, switch to this generic approach. Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/configfs.c | 27 ++- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 7564814..b6aae63 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -54,7 +54,6 @@ struct gadget_info { struct list_head string_list; struct list_head available_func; - const char *udc_name; #ifdef CONFIG_USB_OTG struct usb_otg_descriptor otg; #endif @@ -230,21 +229,21 @@ static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi, static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page) { - return sprintf(page, %s\n, gi-udc_name ?: ); + return sprintf(page, %s\n, gi-composite.gadget_driver.udc_name ?: ); } static int unregister_gadget(struct gadget_info *gi) { int ret; - if (!gi-udc_name) + if (!gi-composite.gadget_driver.udc_name) return -ENODEV; ret = usb_gadget_unregister_driver(gi-composite.gadget_driver); if (ret) return ret; - kfree(gi-udc_name); - gi-udc_name = NULL; + kfree(gi-composite.gadget_driver.udc_name); + gi-composite.gadget_driver.udc_name = NULL; return 0; } @@ -267,14 +266,16 @@ static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi, if (ret) goto err; } else { - if (gi-udc_name) { + if (gi-composite.gadget_driver.udc_name) { ret = -EBUSY; goto err; } - ret = usb_udc_attach_driver(name, gi-composite.gadget_driver); - if (ret) + gi-composite.gadget_driver.udc_name = name; + ret = usb_gadget_probe_driver(gi-composite.gadget_driver); + if (ret) { + gi-composite.gadget_driver.udc_name = NULL; goto err; - gi-udc_name = name; + } } mutex_unlock(gi-lock); return len; @@ -438,9 +439,9 @@ static int config_usb_cfg_unlink( * remove the function. */ mutex_lock(gi-lock); - if (gi-udc_name) + if (gi-composite.gadget_driver.udc_name) unregister_gadget(gi); - WARN_ON(gi-udc_name); + WARN_ON(gi-composite.gadget_driver.udc_name); list_for_each_entry(f, cfg-func_list, list) { if (f-fi == fi) { @@ -917,10 +918,10 @@ static int os_desc_unlink(struct config_item *os_desc_ci, struct usb_composite_dev *cdev = gi-cdev; mutex_lock(gi-lock); - if (gi-udc_name) + if (gi-composite.gadget_driver.udc_name) unregister_gadget(gi); cdev-os_desc_config = NULL; - WARN_ON(gi-udc_name); + WARN_ON(gi-composite.gadget_driver.udc_name); mutex_unlock(gi-lock); return 0; } -- 1.9.1 -- 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
[PATCHv3 5/5] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Change behavior during registration of gadgets and gadget drivers in udc-core. Instead of previous approach when for successful probe of usb gadget driver at least one usb gadget should be already registered use another one where gadget drivers and gadgets can be registered in udc-core independently. Independent registration of gadgets and gadget drivers is useful for built-in into kernel gadget and gadget driver case - because it's possible that gadget is really probed only on late_init stage (due to deferred probe) whereas gadget driver's probe is silently failed on module_init stage due to no any UDC added. Also it is useful for modules case - now there is no difference what module to insert first: gadget module or gadget driver one. Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 51 ++- include/linux/usb/gadget.h| 2 ++ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index a960f3f..9e82497 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -48,8 +48,11 @@ struct usb_udc { static struct class *udc_class; static LIST_HEAD(udc_list); +static LIST_HEAD(gadget_driver_pending_list); static DEFINE_MUTEX(udc_lock); +static int udc_bind_to_driver(struct usb_udc *udc, + struct usb_gadget_driver *driver); /* - */ #ifdef CONFIG_HAS_DMA @@ -243,6 +246,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)) { struct usb_udc *udc; + struct usb_gadget_driver *pgadget; int ret = -ENOMEM; udc = kzalloc(sizeof(*udc), GFP_KERNEL); @@ -288,6 +292,18 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); + /* pick up one of pending gadget drivers */ + list_for_each_entry(pgadget, gadget_driver_pending_list, pending) { + if (!pgadget-udc_name || strcmp(pgadget-udc_name, + dev_name(udc-dev)) == 0) { + ret = udc_bind_to_driver(udc, pgadget); + if (ret) + goto err4; + list_del(pgadget-pending); + break; + } + } + mutex_unlock(udc_lock); return 0; @@ -364,10 +380,11 @@ found: dev_vdbg(gadget-dev.parent, unregistering gadget\n); list_del(udc-list); - mutex_unlock(udc_lock); - - if (udc-driver) + if (udc-driver) { + list_add(udc-driver-pending, gadget_driver_pending_list); usb_gadget_remove_driver(udc); + } + mutex_unlock(udc_lock); kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); @@ -426,24 +443,26 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) if (!ret) break; } - if (ret) - ret = -ENODEV; - else if (udc-driver) - ret = -EBUSY; - else + if (!ret udc-driver) { + mutex_unlock(udc_lock); + return -EBUSY; + } else if (!ret) { goto found; + } } else { list_for_each_entry(udc, udc_list, list) { /* For now we take the first one */ if (!udc-driver) goto found; } - ret = -ENODEV; } - pr_debug(couldn't find an available UDC\n); + list_add_tail(driver-pending, gadget_driver_pending_list); + pr_info(udc-core: couldn't find an available UDC + - added [%s] to list of pending drivers\n, + driver-function); mutex_unlock(udc_lock); - return ret; + return 0; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(udc_lock); @@ -469,6 +488,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) break; } + if (ret) { + struct usb_gadget_driver *tmp; + + list_for_each_entry(tmp, gadget_driver_pending_list, pending) + if (tmp == driver) { + list_del(driver-pending); + ret = 0; + break; + } + } mutex_unlock(udc_lock); return ret; } diff --git a/include/linux/usb
[PATCHv3 1/5] usb: gadget: bind UDC by name passed via usb_gadget_driver structure
Introduce new 'udc_name' member to usb_gadget_driver structure. The 'udc_name' is a name of UDC that usb_gadget_driver should be bound to. If udc_name is NULL, it will be bound to any available UDC. Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 25 - include/linux/usb/gadget.h| 4 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 5a81cb0..e1079e08 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -440,21 +440,36 @@ EXPORT_SYMBOL_GPL(usb_udc_attach_driver); int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; - int ret; + int ret = -ENODEV; if (!driver || !driver-bind || !driver-setup) return -EINVAL; mutex_lock(udc_lock); - list_for_each_entry(udc, udc_list, list) { - /* For now we take the first one */ - if (!udc-driver) + if (driver-udc_name) { + list_for_each_entry(udc, udc_list, list) { + ret = strcmp(driver-udc_name, dev_name(udc-dev)); + if (!ret) + break; + } + if (ret) + ret = -ENODEV; + else if (udc-driver) + ret = -EBUSY; + else goto found; + } else { + list_for_each_entry(udc, udc_list, list) { + /* For now we take the first one */ + if (!udc-driver) + goto found; + } + ret = -ENODEV; } pr_debug(couldn't find an available UDC\n); mutex_unlock(udc_lock); - return -ENODEV; + return ret; found: ret = udc_bind_to_driver(udc, driver); mutex_unlock(udc_lock); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index e2f00fd..3e7aab1 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -821,6 +821,8 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) * @reset: Invoked on USB bus reset. It is mandatory for all gadget drivers * and should be called in_interrupt. * @driver: Driver model state for this driver. + * @udc_name: A name of UDC this driver should be bound to. If udc_name is NULL, + * this driver will be bound to any available UDC. * * Devices are disabled till a gadget driver successfully bind()s, which * means the driver will handle setup() requests needed to enumerate (and @@ -881,6 +883,8 @@ struct usb_gadget_driver { /* FIXME support safe rmmod */ struct device_driverdriver; + + char*udc_name; }; -- 1.9.1 -- 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
[PATCHv3 3/5] usb: gadget: udc-core: remove unused usb_udc_attach_driver()
Now when last user of usb_udc_attach_driver() is switched to passing UDC name via usb_gadget_driver struct, it's safe to remove this function Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 26 -- include/linux/usb/gadget.h| 2 -- 2 files changed, 28 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index e1079e08..a960f3f 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -411,32 +411,6 @@ err1: return ret; } -int usb_udc_attach_driver(const char *name, struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - mutex_lock(udc_lock); - list_for_each_entry(udc, udc_list, list) { - ret = strcmp(name, dev_name(udc-dev)); - if (!ret) - break; - } - if (ret) { - ret = -ENODEV; - goto out; - } - if (udc-driver) { - ret = -EBUSY; - goto out; - } - ret = udc_bind_to_driver(udc, driver); -out: - mutex_unlock(udc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(usb_udc_attach_driver); - int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3e7aab1..6070e8d 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -930,8 +930,6 @@ extern int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)); extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget); extern void usb_del_gadget_udc(struct usb_gadget *gadget); -extern int usb_udc_attach_driver(const char *name, - struct usb_gadget_driver *driver); /*-*/ -- 1.9.1 -- 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
[PATCHv3 4/5] usb: gadget: legacy: don't use __init/__exit attributes for bind/unbind path
In order to prepare to independent gadgets and gadget drivers registration in udc-core, some of the functions can't have __init/__exit attributes (almost only bind/unbind callbacks are affected) Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/legacy/acm_ms.c | 6 +++--- drivers/usb/gadget/legacy/audio.c| 6 +++--- drivers/usb/gadget/legacy/cdc2.c | 6 +++--- drivers/usb/gadget/legacy/dbgp.c | 2 +- drivers/usb/gadget/legacy/ether.c| 8 drivers/usb/gadget/legacy/gmidi.c| 6 +++--- drivers/usb/gadget/legacy/hid.c | 6 +++--- drivers/usb/gadget/legacy/mass_storage.c | 4 ++-- drivers/usb/gadget/legacy/multi.c| 16 drivers/usb/gadget/legacy/ncm.c | 6 +++--- drivers/usb/gadget/legacy/nokia.c| 6 +++--- drivers/usb/gadget/legacy/printer.c | 6 +++--- drivers/usb/gadget/legacy/serial.c | 2 +- drivers/usb/gadget/legacy/webcam.c | 4 ++-- drivers/usb/gadget/legacy/zero.c | 2 +- 15 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index c30b7b5..3a48aab 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -121,7 +121,7 @@ static struct usb_function *f_msg; /* * We _always_ have both ACM and mass storage functions. */ -static int __init acm_ms_do_config(struct usb_configuration *c) +static int acm_ms_do_config(struct usb_configuration *c) { struct fsg_opts *opts; int status; @@ -174,7 +174,7 @@ static struct usb_configuration acm_ms_config_driver = { /*-*/ -static int __init acm_ms_bind(struct usb_composite_dev *cdev) +static int acm_ms_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev-gadget; struct fsg_opts *opts; @@ -249,7 +249,7 @@ fail_get_msg: return status; } -static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) +static int acm_ms_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_msg); usb_put_function_instance(fi_msg); diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index f46a395..ba95518 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -167,7 +167,7 @@ static const struct usb_descriptor_header *otg_desc[] = { /*-*/ -static int __init audio_do_config(struct usb_configuration *c) +static int audio_do_config(struct usb_configuration *c) { int status; @@ -216,7 +216,7 @@ static struct usb_configuration audio_config_driver = { /*-*/ -static int __init audio_bind(struct usb_composite_dev *cdev) +static int audio_bind(struct usb_composite_dev *cdev) { #ifndef CONFIG_GADGET_UAC1 struct f_uac2_opts *uac2_opts; @@ -276,7 +276,7 @@ fail: return status; } -static int __exit audio_unbind(struct usb_composite_dev *cdev) +static int audio_unbind(struct usb_composite_dev *cdev) { #ifdef CONFIG_GADGET_UAC1 if (!IS_ERR_OR_NULL(f_uac1)) diff --git a/drivers/usb/gadget/legacy/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c index 2e85d94..8d1985c 100644 --- a/drivers/usb/gadget/legacy/cdc2.c +++ b/drivers/usb/gadget/legacy/cdc2.c @@ -104,7 +104,7 @@ static struct usb_function_instance *fi_ecm; /* * We _always_ have both CDC ECM and CDC ACM functions. */ -static int __init cdc_do_config(struct usb_configuration *c) +static int cdc_do_config(struct usb_configuration *c) { int status; @@ -153,7 +153,7 @@ static struct usb_configuration cdc_config_driver = { /*-*/ -static int __init cdc_bind(struct usb_composite_dev *cdev) +static int cdc_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev-gadget; struct f_ecm_opts *ecm_opts; @@ -211,7 +211,7 @@ fail: return status; } -static int __exit cdc_unbind(struct usb_composite_dev *cdev) +static int cdc_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_acm); usb_put_function_instance(fi_serial); diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c index 633683a..7c42b01 100644 --- a/drivers/usb/gadget/legacy/dbgp.c +++ b/drivers/usb/gadget/legacy/dbgp.c @@ -284,7 +284,7 @@ fail_1: return -ENODEV; } -static int __init dbgp_bind(struct usb_gadget *gadget, +static int dbgp_bind(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { int err, stp; diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget/legacy/ether.c index c5fdc61..4283969 100644 --- a/drivers/usb
Re: [PATCH 1/2] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Hi Alan, On Mon, Feb 9, 2015 at 10:00 PM, Alan Stern st...@rowland.harvard.edu wrote: On Mon, 9 Feb 2015, Krzysztof Opasiak wrote: Why bother matching by name? Why not simply take the first available UDC? Because you may have more than one udc. This would allow to pick one by name just like using configfs interface. Clearly it would be more flexible to allow the user to do the matching, the way configfs does (sysfs too). Main feature of my path is not only deferred binding of gadget driver, but also possibility to register/unregister udc at any time. This is useful for user who can load, for example, udc module if needed and unload it safely, not touching gadget driver. We can already do that with the existing code. There's no need for a patch. Also, it's not clear that the existing gadget drivers will work properly if they are unbound from one UDC and then bound again to another one. They were not written with that sort of thing in mind. What you have described is one of basics configfs features. You should be able to bind and unbind your gadget whenever you want and it should work properly after doing: ## create gadget $ echo udc.0 UDC $ echo UDC $ echo udc.1 UDC Function shouldn't care which udc it has been bound previously. Only current one is important and on each unbind each function should cleanup its state and prepare to be bound to another udc. Configfs interface doesn't prohibit this and I haven't seen any info about such restriction. It's not prohibited, but it also was never required. Therefore it may not be implemented in all gadget drivers. If some function is not working in such situation there is a bug in that function and it should be fixed. That's fine. I wasn't pointing out a fundamental limitation, just a fact that will have to be taken into account. Anyway, instead of going through all this, why not do what I suggested earlier (see http://marc.info/?l=linux-usbm=139888691230119w=2) and create a gadget bus type? That would give userspace explicit control over which gadget driver was bound to which UDC. Or maybe that's not a very good fit with the existing code, since most gadget drivers assume they will be bound to only one UDC at a time. So instead, why not create a sysfs interface that allows userspace to control which gadget drivers are bound to which UDCs? As I recall, the original problem people were complaining about was deferred probing. They didn't need fancy matching; all they wanted was the ability to bind a gadget driver to a UDC some time after the gadget driver was loaded and initialized. Something simple like Robert Baldyga's patch is enough to do that. I looked over my patch and see that it doesn't automatically rebind gadget driver to another available UDC after previous UDC is unbound. The Gadget Bus mentioned previously is good thing but so far it seems there is no users of such approach. So I left only deferred registration from my patch. I still keep it inside of udc-core since we also need to keep tracking UDC name if somebody wanted to bind gadget driver to specific UDC and it looks like good place to maintain this. I'll send second version of patches soon -- Best regards, Ruslan Bilvol -- 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] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Hi Krzysztof, On Tue, Feb 10, 2015 at 10:47 AM, Krzysztof Opasiak k.opas...@samsung.com wrote: -Original Message- From: Ruslan Bilovol [mailto:ruslan.bilo...@gmail.com] Sent: Tuesday, February 10, 2015 12:46 AM To: Alan Stern Cc: Krzysztof Opasiak; Peter Chen; linux-usb@vger.kernel.org; linux-ker...@vger.kernel.org; Balbi, Felipe; gre...@linuxfoundation.org; Andrzej Pietrasiewicz Subject: Re: [PATCH 1/2] usb: gadget: udc-core: independent registration of gadgets and gadget drivers Hi guys, On Mon, Feb 9, 2015 at 10:00 PM, Alan Stern st...@rowland.harvard.edu wrote: On Mon, 9 Feb 2015, Krzysztof Opasiak wrote: Why bother matching by name? Why not simply take the first available UDC? Because you may have more than one udc. This would allow to pick one by name just like using configfs interface. Clearly it would be more flexible to allow the user to do the matching, the way configfs does (sysfs too). Main feature of my path is not only deferred binding of gadget driver, but also possibility to register/unregister udc at any time. This is useful for user who can load, for example, udc module if needed and unload it safely, not touching gadget driver. We can already do that with the existing code. There's no need for a patch. Also, it's not clear that the existing gadget drivers will work properly if they are unbound from one UDC and then bound again to another one. They were not written with that sort of thing in mind. What you have described is one of basics configfs features. You should be able to bind and unbind your gadget whenever you want and it should work properly after doing: ## create gadget $ echo udc.0 UDC $ echo UDC $ echo udc.1 UDC Function shouldn't care which udc it has been bound previously. Only current one is important and on each unbind each function should cleanup its state and prepare to be bound to another udc. Configfs interface doesn't prohibit this and I haven't seen any info about such restriction. Thank you Krzysztof for this explanation that makes things more clear for reviewers. It's not prohibited, but it also was never required. Therefore it may not be implemented in all gadget drivers. If some function is not working in such situation there is a bug in that function and it should be fixed. That's fine. I wasn't pointing out a fundamental limitation, just a fact that will have to be taken into account. I also don't see any restrictions to bind/unbind gadget driver few times and in case of such bug we just can fix it. I didn't see any issue with gadget drivers that I used for verification, however, to be honest, I didn't test it with all possible ones. Anyway, it should work in legacy way (one gadget driver is bound to one uds) so current behavior at least is not broken. Anyway, instead of going through all this, why not do what I suggested earlier (see http://marc.info/?l=linux-usbm=139888691230119w=2) and create a gadget bus type? That would give userspace explicit control over which gadget driver was bound to which UDC. Exactly, my patch transforms udc-core to something like tiny bus with very basic functionality. But in mentioned mailthread I see good ideas that is possible to implement with small overhead. Or maybe that's not a very good fit with the existing code, since most gadget drivers assume they will be bound to only one UDC at a time. So instead, why not create a sysfs interface that allows userspace to control which gadget drivers are bound to which UDCs? As I recall, the original problem people were complaining about was deferred probing. They didn't need fancy matching; all they wanted was the ability to bind a gadget driver to a UDC some time after the gadget driver was loaded and initialized. Something simple like Robert Baldyga's patch is enough to do that. This simplicity is also a limitation. As I mentioned before, sometimes it is needed to be able to bind/unbind gadget driver multiple times to different UDCs. A real case I faced recently is SoC with HighSpeed-only and SuperSpeed-only UDCs. SuperSpeed-only UDC can't work on USB 2.0 speeds and vice versa. The system has USB3.0 USB connector with soldered HS lines from mentioned HS-only and SS lines from SS-only UDCs. Each UDC has it's own device driver, so if we want to use both of them with one gadget driver, we must be able to bind/unbind it multiple times to different UDCs. Another one usecase is users who can unload udc drivers without carrying about gadget drivers. Third usecase is, for example, developers who can switch between dummy_hcd and real UDC hardware without unloading gadget driver. Just a stupid question. Why don't you use configfs composite gadget instead of legacy gadgets? In my opinion all things which you have described
Re: [PATCH 1/2] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Hi guys, On Mon, Feb 9, 2015 at 10:00 PM, Alan Stern st...@rowland.harvard.edu wrote: On Mon, 9 Feb 2015, Krzysztof Opasiak wrote: Why bother matching by name? Why not simply take the first available UDC? Because you may have more than one udc. This would allow to pick one by name just like using configfs interface. Clearly it would be more flexible to allow the user to do the matching, the way configfs does (sysfs too). Main feature of my path is not only deferred binding of gadget driver, but also possibility to register/unregister udc at any time. This is useful for user who can load, for example, udc module if needed and unload it safely, not touching gadget driver. We can already do that with the existing code. There's no need for a patch. Also, it's not clear that the existing gadget drivers will work properly if they are unbound from one UDC and then bound again to another one. They were not written with that sort of thing in mind. What you have described is one of basics configfs features. You should be able to bind and unbind your gadget whenever you want and it should work properly after doing: ## create gadget $ echo udc.0 UDC $ echo UDC $ echo udc.1 UDC Function shouldn't care which udc it has been bound previously. Only current one is important and on each unbind each function should cleanup its state and prepare to be bound to another udc. Configfs interface doesn't prohibit this and I haven't seen any info about such restriction. Thank you Krzysztof for this explanation that makes things more clear for reviewers. It's not prohibited, but it also was never required. Therefore it may not be implemented in all gadget drivers. If some function is not working in such situation there is a bug in that function and it should be fixed. That's fine. I wasn't pointing out a fundamental limitation, just a fact that will have to be taken into account. I also don't see any restrictions to bind/unbind gadget driver few times and in case of such bug we just can fix it. I didn't see any issue with gadget drivers that I used for verification, however, to be honest, I didn't test it with all possible ones. Anyway, it should work in legacy way (one gadget driver is bound to one uds) so current behavior at least is not broken. Anyway, instead of going through all this, why not do what I suggested earlier (see http://marc.info/?l=linux-usbm=139888691230119w=2) and create a gadget bus type? That would give userspace explicit control over which gadget driver was bound to which UDC. Exactly, my patch transforms udc-core to something like tiny bus with very basic functionality. But in mentioned mailthread I see good ideas that is possible to implement with small overhead. Or maybe that's not a very good fit with the existing code, since most gadget drivers assume they will be bound to only one UDC at a time. So instead, why not create a sysfs interface that allows userspace to control which gadget drivers are bound to which UDCs? As I recall, the original problem people were complaining about was deferred probing. They didn't need fancy matching; all they wanted was the ability to bind a gadget driver to a UDC some time after the gadget driver was loaded and initialized. Something simple like Robert Baldyga's patch is enough to do that. This simplicity is also a limitation. As I mentioned before, sometimes it is needed to be able to bind/unbind gadget driver multiple times to different UDCs. A real case I faced recently is SoC with HighSpeed-only and SuperSpeed-only UDCs. SuperSpeed-only UDC can't work on USB 2.0 speeds and vice versa. The system has USB3.0 USB connector with soldered HS lines from mentioned HS-only and SS lines from SS-only UDCs. Each UDC has it's own device driver, so if we want to use both of them with one gadget driver, we must be able to bind/unbind it multiple times to different UDCs. Another one usecase is users who can unload udc drivers without carrying about gadget drivers. Third usecase is, for example, developers who can switch between dummy_hcd and real UDC hardware without unloading gadget driver. I'll work on improved version and will send new patch soon... Best regards, Ruslan Alan Stern -- 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] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Hi Alan, On Thu, Jan 29, 2015 at 5:56 PM, Alan Stern st...@rowland.harvard.edu wrote: On Thu, 29 Jan 2015, Ruslan Bilovol wrote: Change behavior during registration of gadgets and gadget drivers in udc-core. Instead of previous approach when for successful probe of usb gadget driver at least one usb gadget should be already registered use another one where gadget drivers and gadgets can be registered in udc-core independently. Independent registration of gadgets and gadget drivers is useful for built-in into kernel gadget and gadget driver case - because it's possible that gadget is really probed only on late_init stage (due to deferred probe) whereas gadget driver's probe is silently failed on module_init stage due to no any UDC added. Also it is useful for modules case - now there is no difference what module to insert first: gadget module or gadget driver one. It's possible to do all this much more simply. In fact, I posted a patch some time ago to do exactly this (but I can't find a copy of it anywhere). Unfortunately I didn't find your patch. Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 113 +++--- 1 file changed, 105 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index e31d574..4c9412b 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -43,13 +43,23 @@ struct usb_udc { struct usb_gadget_driver*driver; struct usb_gadget *gadget; struct device dev; + boolbind_by_name; + struct list_headlist; +}; + +struct pending_gadget_driver { + struct usb_gadget_driver*driver; + char*udc_name; struct list_headlist; }; You don't need all this stuff. What's the point of keeping track of names? If there are any unbound gadget drivers pending, a newly registered UDC should bind to the first one available. It's because gadget driver may be bound to usb_gadget in two ways: - standard way - in this case any available udc will be picked up - by name of udc, in this case only matching udc will be picked up Main feature of my path is not only deferred binding of gadget driver, but also possibility to register/unregister udc at any time. This is useful for user who can load, for example, udc module if needed and unload it safely, not touching gadget driver. Another example is USB device controllers that consist of pair of HS+SS controllers, each one having its own udc driver. In this case it's possible to switch SS/HS by registering/unregistering corresponding udc and not touching gadget driver. I did all of this inside of udc-core because it looks like to be best place for udc - gadget driver housekeeping. Also it is verified on lot of combinations of udc and gadget drivers that can be built-in or build as modules Best regards, Ruslan Just add a pending list_head into the usb_gadget_driver structure and forget about all the rest. (Or try to find my patch in the mailing list archives somehow see if you think it needs to be changed.) Alan Stern -- 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 2/2] usb: gadget: legacy: don't use __init/__exit attributes for bind/unbind path
Since it's possible now to do independent gadget and gadget driver registration in udc-core, some of the functions can't have __init/__exit attributes (almost bind/unbind callbacks are affected) Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/legacy/acm_ms.c | 6 +++--- drivers/usb/gadget/legacy/audio.c| 6 +++--- drivers/usb/gadget/legacy/cdc2.c | 6 +++--- drivers/usb/gadget/legacy/dbgp.c | 2 +- drivers/usb/gadget/legacy/ether.c| 8 drivers/usb/gadget/legacy/gmidi.c| 6 +++--- drivers/usb/gadget/legacy/hid.c | 6 +++--- drivers/usb/gadget/legacy/mass_storage.c | 4 ++-- drivers/usb/gadget/legacy/multi.c| 16 drivers/usb/gadget/legacy/ncm.c | 6 +++--- drivers/usb/gadget/legacy/nokia.c| 6 +++--- drivers/usb/gadget/legacy/printer.c | 6 +++--- drivers/usb/gadget/legacy/serial.c | 2 +- drivers/usb/gadget/legacy/webcam.c | 4 ++-- drivers/usb/gadget/legacy/zero.c | 2 +- 15 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index c30b7b5..3a48aab 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -121,7 +121,7 @@ static struct usb_function *f_msg; /* * We _always_ have both ACM and mass storage functions. */ -static int __init acm_ms_do_config(struct usb_configuration *c) +static int acm_ms_do_config(struct usb_configuration *c) { struct fsg_opts *opts; int status; @@ -174,7 +174,7 @@ static struct usb_configuration acm_ms_config_driver = { /*-*/ -static int __init acm_ms_bind(struct usb_composite_dev *cdev) +static int acm_ms_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev-gadget; struct fsg_opts *opts; @@ -249,7 +249,7 @@ fail_get_msg: return status; } -static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) +static int acm_ms_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_msg); usb_put_function_instance(fi_msg); diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index f46a395..ba95518 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -167,7 +167,7 @@ static const struct usb_descriptor_header *otg_desc[] = { /*-*/ -static int __init audio_do_config(struct usb_configuration *c) +static int audio_do_config(struct usb_configuration *c) { int status; @@ -216,7 +216,7 @@ static struct usb_configuration audio_config_driver = { /*-*/ -static int __init audio_bind(struct usb_composite_dev *cdev) +static int audio_bind(struct usb_composite_dev *cdev) { #ifndef CONFIG_GADGET_UAC1 struct f_uac2_opts *uac2_opts; @@ -276,7 +276,7 @@ fail: return status; } -static int __exit audio_unbind(struct usb_composite_dev *cdev) +static int audio_unbind(struct usb_composite_dev *cdev) { #ifdef CONFIG_GADGET_UAC1 if (!IS_ERR_OR_NULL(f_uac1)) diff --git a/drivers/usb/gadget/legacy/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c index 2e85d94..8d1985c 100644 --- a/drivers/usb/gadget/legacy/cdc2.c +++ b/drivers/usb/gadget/legacy/cdc2.c @@ -104,7 +104,7 @@ static struct usb_function_instance *fi_ecm; /* * We _always_ have both CDC ECM and CDC ACM functions. */ -static int __init cdc_do_config(struct usb_configuration *c) +static int cdc_do_config(struct usb_configuration *c) { int status; @@ -153,7 +153,7 @@ static struct usb_configuration cdc_config_driver = { /*-*/ -static int __init cdc_bind(struct usb_composite_dev *cdev) +static int cdc_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev-gadget; struct f_ecm_opts *ecm_opts; @@ -211,7 +211,7 @@ fail: return status; } -static int __exit cdc_unbind(struct usb_composite_dev *cdev) +static int cdc_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_acm); usb_put_function_instance(fi_serial); diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c index 633683a..7c42b01 100644 --- a/drivers/usb/gadget/legacy/dbgp.c +++ b/drivers/usb/gadget/legacy/dbgp.c @@ -284,7 +284,7 @@ fail_1: return -ENODEV; } -static int __init dbgp_bind(struct usb_gadget *gadget, +static int dbgp_bind(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { int err, stp; diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget/legacy/ether.c index c5fdc61..4283969 100644 --- a/drivers/usb
[PATCH 1/2] usb: gadget: udc-core: independent registration of gadgets and gadget drivers
Change behavior during registration of gadgets and gadget drivers in udc-core. Instead of previous approach when for successful probe of usb gadget driver at least one usb gadget should be already registered use another one where gadget drivers and gadgets can be registered in udc-core independently. Independent registration of gadgets and gadget drivers is useful for built-in into kernel gadget and gadget driver case - because it's possible that gadget is really probed only on late_init stage (due to deferred probe) whereas gadget driver's probe is silently failed on module_init stage due to no any UDC added. Also it is useful for modules case - now there is no difference what module to insert first: gadget module or gadget driver one. Signed-off-by: Ruslan Bilovol ruslan.bilo...@gmail.com --- drivers/usb/gadget/udc/udc-core.c | 113 +++--- 1 file changed, 105 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index e31d574..4c9412b 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -43,13 +43,23 @@ struct usb_udc { struct usb_gadget_driver*driver; struct usb_gadget *gadget; struct device dev; + boolbind_by_name; + struct list_headlist; +}; + +struct pending_gadget_driver { + struct usb_gadget_driver*driver; + char*udc_name; struct list_headlist; }; static struct class *udc_class; static LIST_HEAD(udc_list); +static LIST_HEAD(gadget_driver_pending_list); static DEFINE_MUTEX(udc_lock); +static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver, + bool bind_by_name); /* - */ #ifdef CONFIG_HAS_DMA @@ -244,6 +254,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, { struct usb_udc *udc; int ret = -ENOMEM; + struct pending_gadget_driver *pending; udc = kzalloc(sizeof(*udc), GFP_KERNEL); if (!udc) @@ -288,6 +299,24 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); + if (!list_empty(gadget_driver_pending_list)) { + pending = list_first_entry(gadget_driver_pending_list, + struct pending_gadget_driver, list); + + if (pending-udc_name) { + if (!strcmp(pending-udc_name, dev_name(udc-dev))) { + udc_bind_to_driver(udc, pending-driver, true); + list_del(pending-list); + kfree(pending-udc_name); + kfree(pending); + } + } else { + udc_bind_to_driver(udc, pending-driver, false); + list_del(pending-list); + kfree(pending); + } + } + mutex_unlock(udc_lock); return 0; @@ -364,10 +393,32 @@ found: dev_vdbg(gadget-dev.parent, unregistering gadget\n); list_del(udc-list); - mutex_unlock(udc_lock); - if (udc-driver) + if (udc-driver) { + struct pending_gadget_driver *pending; + + pending = kzalloc(sizeof(*pending), GFP_KERNEL); + if (!pending) + goto err; + + if (udc-bind_by_name) { + pending-udc_name = kstrdup(dev_name(udc-dev), + GFP_KERNEL); + if (!pending-udc_name) { + kfree(pending); + goto err; + } + } + + pending-driver = udc-driver; + list_add_tail(pending-list, gadget_driver_pending_list); + + pr_info(udc-core: added [%s] to list of pending drivers\n, + pending-driver-function); +err: usb_gadget_remove_driver(udc); + } + mutex_unlock(udc_lock); kobject_uevent(udc-dev.kobj, KOBJ_REMOVE); flush_work(gadget-work); @@ -378,7 +429,8 @@ EXPORT_SYMBOL_GPL(usb_del_gadget_udc); /* - */ -static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver) +static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver, + bool bind_by_name) { int ret
[PATCH 0/2] usb/gadget: independent registration of gadgets and gadget
This patchset adds independent registration of gadgets and gadget drivers to udc-core. This is very useful for built-in modules into kernel case since it's possible situation that gadget driver is probing at a time when no gadgets are registered in udc-core. In this case instead of silently failing without of any attempt to recover, with independent registration of gadgets and gadget drivers there is no matter in which order gadgets and gadget drivers are probed/registered. Also it's possible to add/remove gadgets or gadget drivers many times since it's now correctly handled by the udc-core This patch has side-effect on gadget drivers that had __init/__exit attributes on some paths like bind/unbind and (since bind/unbind may happen at any time) should not use them now. This is covered by second patch (please let me know if I need to break it into separate patches for each gadget driver) Ruslan Bilovol (2): usb: gadget: udc-core: independent registration of gadgets and gadget drivers usb: gadget: legacy: don't use __init/__exit attributes for bind/unbind path drivers/usb/gadget/legacy/acm_ms.c | 6 +- drivers/usb/gadget/legacy/audio.c| 6 +- drivers/usb/gadget/legacy/cdc2.c | 6 +- drivers/usb/gadget/legacy/dbgp.c | 2 +- drivers/usb/gadget/legacy/ether.c| 8 +-- drivers/usb/gadget/legacy/gmidi.c| 6 +- drivers/usb/gadget/legacy/hid.c | 6 +- drivers/usb/gadget/legacy/mass_storage.c | 4 +- drivers/usb/gadget/legacy/multi.c| 16 ++--- drivers/usb/gadget/legacy/ncm.c | 6 +- drivers/usb/gadget/legacy/nokia.c| 6 +- drivers/usb/gadget/legacy/printer.c | 6 +- drivers/usb/gadget/legacy/serial.c | 2 +- drivers/usb/gadget/legacy/webcam.c | 4 +- drivers/usb/gadget/legacy/zero.c | 2 +- drivers/usb/gadget/udc/udc-core.c| 112 --- 16 files changed, 147 insertions(+), 51 deletions(-) -- 1.9.1 -- 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: usb media detection issue on USB_MUSB_HDRC on kernel 3.17
Hi Enric On Wed, Oct 29, 2014 at 1:44 PM, Enric Balletbo Serra eballe...@gmail.com wrote: Hi all, 2014-10-26 10:10 GMT+01:00 Angelo Dureghello angel...@gmail.com: Had some progresses: on kernel 3.17, musb controller driver is set to start as OTG mode as default. So as first thing, since my board has ID pin shorted to ground, i changed the default mode to MUSB_HOST., as it was on kernel 3.5.1 So with same settings of 3.5.1 now key is detected correctly at first insertion, but after a removal, the stick is not detected anymore. Issue seems visible in drivers/usb/musb/da8xx.c, inside irqreturn_t da8xx_musb_interrupt() routine. looking the /sys fs, i see that the mode moves in time order as: |boot: vbus off b_idle|| boot: vbus off a_wait_vrise|| insertion: vbus off a_host| removal:vbus off b_idle After last b_host, the state never moves back to a_wait_vrise. After the removal, the interrupt call irqreturn_t da8xx_musb_interrupt() seems broken and seems never called anymore. Regards. I'll add more information to this thread. Seems MUSB is also broken on OMAP3 boards, booting in OTG mode I'm not able to make it work when a pendrive is connected to the port. Forcing HOST mode I get following messages: [ 13.244567] usb 2-1: new high-speed USB device number 2 using musb-hdrc [ 13.503234] usb 2-1: device v058f p6387 is not supported [ 13.592346] usb usb2-port1: unable to enumerate USB device You need to disable CONFIG_USB_OTG_WHITELIST option to avoid this. Or add your device to white list of supported devices. Best regards, Ruslan OTOH the OTG port as gadget works. Regards, Enric -- 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 -- Best regards, Ruslan Bilvol -- 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: omap4 ehci sporadic resume issue
Hello guys, On Thu, Jun 27, 2013 at 8:56 PM, Michael Trimarchi mich...@amarulasolutions.com wrote: Hi Roger On Thu, Jun 27, 2013 at 05:49:41PM +0300, Roger Quadros wrote: +Ruslan On 06/27/2013 05:17 PM, Michael Trimarchi wrote: Hi Roger On Thu, Jun 27, 2013 at 04:59:38PM +0300, Roger Quadros wrote: Hi Michael, On 06/27/2013 02:51 PM, Michael Trimarchi wrote: Hi I'm working on omap4460 with two ulpi connected to (SMSC3320 - HUB SMSC2514) or (TUSB1210 - HUB SMSC2514). The problem only happen when both port are used and after few suspend resume are triggered. If I use just one port there is no issue on suspend resume. I already covered all TI errata that I know and I'm working on TI kernel. The problem is here [ 77.701934] ehci-omap ehci-omap.0: irq status a004 Async Recl PCD Both ports change status from 001005 to 001009 (you have a log just after). So from host point of view both hub connected are not working in HS mode. After that the omap ehci has gone because the bus can not work in FS and LS and I can not recover from here. Status of transceivers are dumped and they are ok after resume. Do you have any suggestion? I'm not very sure but both ports suddenly changing state like that look like a hardware issue. Also, it is strange that you can reproduce it only when two ports are simultaneously in use. Unfortunately, I can't match your setup with 2 ULPI Yes I know that TI doesn't have any setup like that. ports. I have a OMAP5 uEVM that uses 2 ports but it won't be identical to your setup as they are on HSIC and not ULPI. Did you try errata i693? Yes I have it. It's not clear if I need to wait after ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); polling the suspendM of the SMSC or the suspend status of the PORT or I can switch just after this instruction. Because TI kernel use an msleep of 4 mseconds and then switch. It could be a timing issue on how errata is implemented when I have two ports? How this internal count works? The OMAP EHCI controller transparently sets the suspendM bit of the PHY when you set the PORT_SUSPEND feature on the EHCI port. So you don't need to poll for anything. A delay is necessary. If we apply the errata to the port before a delay the errata doesn't work. /* Use internal 60Mhz clock ULPIBx */ temp_reg = omap_readl(L3INIT_HSUSBHOST_CLKCTRL); temp_reg |= 1 (8 + port); temp_reg = ~(1 (24 + port)); omap_writel(temp_reg, L3INIT_HSUSBHOST_CLKCTRL); /* Wait 2ms to have transceiver transaction */ mdelay(2); /* Use external clock ULPIBx */ temp_reg = ~(1 (8 + port)); temp_reg |= 1 (24 + port); omap_writel(temp_reg, L3INIT_HSUSBHOST_CLKCTRL); Now it's not clear to me what happen if I apply this clock too early (transeceiver still driver the clock) or too late. Any clue? We need to wait 3ms for entire USB bus to go into suspend after setting the PORT_SUSPEND bit. During this time, internal OMAP EHCI logic will communicate with PHY so it is not safe to switch the clocks to internal source. That's why with 2ms delay it fails. 4ms delay (3ms + 1ms for safety) is enough here and is successfully used last few years for production devices. -- Best regards, Ruslan Bilvol What the errata says is that once software sets the PORT_SUSPEND feature, the PHY will got into suspend and cut the PHY clock sooner than required for the EHCI controller to complete its suspend operations. (NOTE: this is only applicable when the PHY is providing the ulpi_clk). Yes this is the case What the workaround does is to just wait for a while (don't know why 4ms), and remux the ulpi_clock to an internal 60MHz clock for a while so that it can complete its suspend operations. What happen if I apply a big delay after PORT_SUSPEND. Will the internal state machine of the omap continue to wait the clock? Michael First time is 18, and then? I think it is 18 for every port suspend. Also, are you suspending and resuming only the USB or the entire system? Whole system. Right the only susbsytem that doens't go to suspend is the FSUSB but this depends on the bootloader. OK. cheers, -roger -- 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 -- 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: omap4 ehci sporadic resume issue
On Thu, Jun 27, 2013 at 10:24 PM, Michael Trimarchi mich...@amarulasolutions.com wrote: Hi On Thu, Jun 27, 2013 at 09:59:35PM +0300, Ruslan Bilovol wrote: Hello guys, On Thu, Jun 27, 2013 at 8:56 PM, Michael Trimarchi mich...@amarulasolutions.com wrote: Hi Roger On Thu, Jun 27, 2013 at 05:49:41PM +0300, Roger Quadros wrote: +Ruslan On 06/27/2013 05:17 PM, Michael Trimarchi wrote: Hi Roger On Thu, Jun 27, 2013 at 04:59:38PM +0300, Roger Quadros wrote: Hi Michael, On 06/27/2013 02:51 PM, Michael Trimarchi wrote: Hi I'm working on omap4460 with two ulpi connected to (SMSC3320 - HUB SMSC2514) or (TUSB1210 - HUB SMSC2514). The problem only happen when both port are used and after few suspend resume are triggered. If I use just one port there is no issue on suspend resume. I already covered all TI errata that I know and I'm working on TI kernel. The problem is here [ 77.701934] ehci-omap ehci-omap.0: irq status a004 Async Recl PCD Both ports change status from 001005 to 001009 (you have a log just after). So from host point of view both hub connected are not working in HS mode. After that the omap ehci has gone because the bus can not work in FS and LS and I can not recover from here. Status of transceivers are dumped and they are ok after resume. Do you have any suggestion? I'm not very sure but both ports suddenly changing state like that look like a hardware issue. Also, it is strange that you can reproduce it only when two ports are simultaneously in use. Unfortunately, I can't match your setup with 2 ULPI Yes I know that TI doesn't have any setup like that. ports. I have a OMAP5 uEVM that uses 2 ports but it won't be identical to your setup as they are on HSIC and not ULPI. Did you try errata i693? Yes I have it. It's not clear if I need to wait after ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); polling the suspendM of the SMSC or the suspend status of the PORT or I can switch just after this instruction. Because TI kernel use an msleep of 4 mseconds and then switch. It could be a timing issue on how errata is implemented when I have two ports? How this internal count works? The OMAP EHCI controller transparently sets the suspendM bit of the PHY when you set the PORT_SUSPEND feature on the EHCI port. So you don't need to poll for anything. A delay is necessary. If we apply the errata to the port before a delay the errata doesn't work. /* Use internal 60Mhz clock ULPIBx */ temp_reg = omap_readl(L3INIT_HSUSBHOST_CLKCTRL); temp_reg |= 1 (8 + port); temp_reg = ~(1 (24 + port)); omap_writel(temp_reg, L3INIT_HSUSBHOST_CLKCTRL); /* Wait 2ms to have transceiver transaction */ mdelay(2); /* Use external clock ULPIBx */ temp_reg = ~(1 (8 + port)); temp_reg |= 1 (24 + port); omap_writel(temp_reg, L3INIT_HSUSBHOST_CLKCTRL); Now it's not clear to me what happen if I apply this clock too early (transeceiver still driver the clock) or too late. Any clue? We need to wait 3ms for entire USB bus to go into suspend after setting the PORT_SUSPEND bit. During this time, internal OMAP EHCI logic will communicate with PHY so it is not safe to switch the clocks to internal source. That's why with 2ms delay it fails. 4ms delay (3ms + 1ms for safety) is enough here and is successfully used last few years for production devices. Well this mdelay is the switch of the clock and not the delay after PORT_SUSPEND. So after writing PORT_SUSPEND I need to wait 4ms and then in 2ms you have a lot of clock to reach the 18 count. Correct? Yes, sorry for confusing :) Moreover, 2ms is more than enough, errata document says about 1ms delay (and probably may be decreased up to few useconds) Anyway I understand, but why both hub connected to the smsc3320 move from HS to FS? So it's not important if there is a drift of delay but it must be = 4ms. Correct? The code works if I just use one port or remove one hub ;) Now the code is like this: temp = ~(PORT_WKCONN_E | PORT_RWC_BITS); temp |= PORT_WKDISC_E | PORT_WKOC_E; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); mdelay(4); omap_ehci_erratum_i693(ehci, ((wIndex 0xff) - 1)); The code of the function is up on this email. Do you have locks around this software workaround? The patch I did against 3.4 linux kernel may be helpful for you in such case: http://review.omapzoom.org/28515 Another patch extends this WA for all OMAP4 SoCs: http://review.omapzoom.org/31108 Regards Ruslan Michael -- Best regards, Ruslan Bilvol What the errata says is that once software sets the PORT_SUSPEND feature, the PHY will got into suspend and cut the PHY clock sooner than required for the EHCI controller to complete its suspend operations. (NOTE: this is only applicable when the PHY is providing
Re: musb throughput issues
Hi Frederik, On Fri, May 10, 2013 at 2:22 PM, Frederik Schmid frederik.sch...@rubico.se wrote: Hi Ruslan, Thanks for the tips! A few comments below: On Friday 10 May 2013 13.54.53 Ruslan Bilovol wrote: Hello Frederic, On Fri, May 10, 2013 at 12:54 PM, Frederik Schmid frederik.sch...@rubico.se wrote: Well, my conclusion is that this setup, IDS-camera + musb, is horribly sensitive to interrupt latency. If the musb-interrupt is blocked for ~100us the pipe is stalled. Most of the interrupts on my target were routed to CPU0 while CPU1 had few. When I re-route the musb interrupts to CPU1 throughput increases to ~120Mbps but I've only reduced the probability of the interrupt being blocked. If you want to increase throughput over musb on omap4, usually next steps help: - route musb IRQ to another CPU if possible Done that. - check if musb uses DMA mode (not PIO) It does. - check if the data (urb) passed to musb is aligned, if not - apply next patch: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id= 8408fd1d83e39bf856d31a36b70bcc53527702fd - play with double packet buffering Didn't check but I applied your patch anyway. Doesn't seem to make any difference. - increase OPP - this will reduce latency I'm not sure what this means. Something to do with power management? Is there something specific I could try? yes. here is some documentation about it: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/power/opp.txt Regards, Ruslan But I can say that on OMAP4 throughput over musb will be lower than over ehci controller because ehci one does many things in HW whereas musb have to do some of them in SW. My scores for musb were ~145 Mbits/s for bulk transfers, but they probably may be increased after additional tuning. The only hope this application has is if MODE1 in the controller could alleviate latency dependence but MODE1 seems quite broken in the hardware? musb_host.c: /* Disadvantage of using mode 1: * It's basically usable only for mass storage class; essentially all * other protocols also terminate transfers on short packets. * ... */ Best regards, Frederik On Friday 10 May 2013 07.26.35 Frederik Schmid wrote: Hi Greg, The kernel is based on 3.4.11 from omapzoom.org (ti-ubuntu-3.4-1487) with Variscite BSP patches from: http://www.variwiki.com/index.php?title=VAR-SOM-OM44_-_Ubuntu_Precise I was expecting 200-250Mbps which is entirly possible on the same chip using its ehci-controller. musb seems to sustain this speed also, for most of the time, until a glitch like the one in the screenshot stalls the pipe. We don't want to use the ehci-controller because it's already bogged down with an ethernet controller. Regards, Frederik On Thursday 09 May 2013 08.12.47 Greg KH wrote: On Thu, May 09, 2013 at 10:44:05AM +0200, Frederik Schmid wrote: Hi, I'm developing a camera application on a TI OMAP4460. I have a cmos usb-camera from IDS (UI-1551-LE-C-HQ) connected to the OTG-port (musb as host) on the OMAP. I get very poor frame rates with this setup reliably. The throughput rate is ~50-70Mbps. (1600x1200,8bpp,3-5fps) I uploaded a screenshot of a packet trace here: http://i.imgur.com/26XL23T.png The host seems to keep up with the camera most of the time but occasionally some kind of glitch causes the host to lag behind and the camera signals STALL because of buffer overrun. What kernel version are you using? And what data rate do you expect to be getting with this hardware configuration? thanks, greg k-h -- 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 -- 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 -- 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 -- 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: musb throughput issues
Hello Frederic, On Fri, May 10, 2013 at 12:54 PM, Frederik Schmid frederik.sch...@rubico.se wrote: Well, my conclusion is that this setup, IDS-camera + musb, is horribly sensitive to interrupt latency. If the musb-interrupt is blocked for ~100us the pipe is stalled. Most of the interrupts on my target were routed to CPU0 while CPU1 had few. When I re-route the musb interrupts to CPU1 throughput increases to ~120Mbps but I've only reduced the probability of the interrupt being blocked. If you want to increase throughput over musb on omap4, usually next steps help: - route musb IRQ to another CPU if possible - check if musb uses DMA mode (not PIO) - check if the data (urb) passed to musb is aligned, if not - apply next patch: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=8408fd1d83e39bf856d31a36b70bcc53527702fd - play with double packet buffering - increase OPP - this will reduce latency But I can say that on OMAP4 throughput over musb will be lower than over ehci controller because ehci one does many things in HW whereas musb have to do some of them in SW. My scores for musb were ~145 Mbits/s for bulk transfers, but they probably may be increased after additional tuning. The only hope this application has is if MODE1 in the controller could alleviate latency dependence but MODE1 seems quite broken in the hardware? musb_host.c: /* Disadvantage of using mode 1: * It's basically usable only for mass storage class; essentially all * other protocols also terminate transfers on short packets. * ... */ Best regards, Frederik On Friday 10 May 2013 07.26.35 Frederik Schmid wrote: Hi Greg, The kernel is based on 3.4.11 from omapzoom.org (ti-ubuntu-3.4-1487) with Variscite BSP patches from: http://www.variwiki.com/index.php?title=VAR-SOM-OM44_-_Ubuntu_Precise I was expecting 200-250Mbps which is entirly possible on the same chip using its ehci-controller. musb seems to sustain this speed also, for most of the time, until a glitch like the one in the screenshot stalls the pipe. We don't want to use the ehci-controller because it's already bogged down with an ethernet controller. Regards, Frederik On Thursday 09 May 2013 08.12.47 Greg KH wrote: On Thu, May 09, 2013 at 10:44:05AM +0200, Frederik Schmid wrote: Hi, I'm developing a camera application on a TI OMAP4460. I have a cmos usb-camera from IDS (UI-1551-LE-C-HQ) connected to the OTG-port (musb as host) on the OMAP. I get very poor frame rates with this setup reliably. The throughput rate is ~50-70Mbps. (1600x1200,8bpp,3-5fps) I uploaded a screenshot of a packet trace here: http://i.imgur.com/26XL23T.png The host seems to keep up with the camera most of the time but occasionally some kind of glitch causes the host to lag behind and the camera signals STALL because of buffer overrun. What kernel version are you using? And what data rate do you expect to be getting with this hardware configuration? thanks, greg k-h -- 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 -- 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 -- Best regards, Ruslan Bilvol -- 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] usb: musb: gadget: fix enumeration on heavy-loaded systems
Hi Ravi, On Tue, Apr 16, 2013 at 7:57 PM, B, Ravi ravib...@ti.com wrote: -Original Message- From: linux-usb-ow...@vger.kernel.org [mailto:linux-usb- ow...@vger.kernel.org] On Behalf Of Bilovol, Ruslan Sent: Tuesday, April 16, 2013 9:12 PM To: Balbi, Felipe; gre...@linuxfoundation.org; linux-usb@vger.kernel.org; linux-ker...@vger.kernel.org Subject: [PATCH] usb: musb: gadget: fix enumeration on heavy-loaded systems From musb point of view, the Address Assignment sequence during device enumeration is next: - first ep0 interrupt: * read the address from USB_REQ_SET_ADDRESS request * set up CSR0L.DataEnd bit (that is ACK signalization for the host) - second ep0 interrupt: * indicates that the request completed successfully * set up musb device address Now musb device should answer to this address From the host perspective, if peripheral device acquires SET_ADDRESS request, it now may be accessed only using that address. However, on heavy loaded systems, time between first and second musb ep0 interrupts may be too long and musb controller misses requests between. What is meant by heavily loaded system? Is the device is heavily loaded during enumeration stage? Why second ep0 interrupt is too long? whether interrupt occurrence to interrupt service is taking too long? I mean production system with aggressive power management and tens of interrupt sources. On such systems and in low CPU frequency case, you may meet condition when time between IRQ firing and ISR entering is increased in few times. In particular case of OMAP4 where I met this issue, time between first and second ep0 interrupt sometimes may be up to 800-900 uS and in this case the USB30CV test fails. If this time is 200-300 uS, the test successfully passes. Unfortunately, this time is not predictable and depends on many factors so this patch ensures we change the address as soon as sent ACK to the host. As result, device enumeration may be unsuccessful. This can be checked on USB3.0 Host and using USB3.0 test suite (from usb.org) running ch9 tests for USB2.0 devices. You mean the usb2.0 musb controller (in device mode) connected to USB3.0 host? Correct. USB2.0 musb controller in device mode, connected to USB3.0 host that runs USB30CV utility for USB2.0 devices Usually 'Addressed state/TD9.1: Device Descriptor Test' will fail The fix consists in checking CSR0L.DataEnd state and assigning the device address in the first ep0 interrupt handling, so delay is as minimal as possible Signed-off-by: Ruslan Bilovol ruslan.bilo...@ti.com --- drivers/usb/musb/musb_gadget_ep0.c | 31 +++ 1 file changed, 31 insertions(+) diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index c9c1ac4..59bc5a5 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -885,6 +885,37 @@ stall: finish: musb_writew(regs, MUSB_CSR0, musb-ackpend); + + /* + * If we are at end of SET_ADDRESS sequence, + * update the address immediately if possible, + * otherwise we may miss packets between + * sending ACK from musb side and musb's next + * interrupt handler firing (in which we update + * the address). At least this fixes next + * USB2.0 ch9 test of USB30CV utility: + * Addressed state - Device Descriptor test + */ + if (musb-set_address (musb-ackpend + MUSB_CSR0_P_DATAEND) + (musb-ep0_state == + MUSB_EP0_STAGE_STATUSIN)) { + u16 ack_delay = 500; + + while ((musb_readw(regs, MUSB_CSR0) + MUSB_CSR0_P_DATAEND) + --ack_delay) { + cpu_relax(); + udelay(1); + } + + if (ack_delay) { + musb-set_address = false; + musb_writeb(mbase, MUSB_FADDR, + musb-address); + } + } + musb-ackpend = 0; } } -- Ravi B
Re: [PATCH] usb: musb: gadget: fix enumeration on heavy-loaded systems
On Wed, Apr 17, 2013 at 3:07 PM, B, Ravi ravib...@ti.com wrote: Ruslan Subject: [PATCH] usb: musb: gadget: fix enumeration on heavy-loaded systems From musb point of view, the Address Assignment sequence during device enumeration is next: - first ep0 interrupt: * read the address from USB_REQ_SET_ADDRESS request * set up CSR0L.DataEnd bit (that is ACK signalization for the host) - second ep0 interrupt: * indicates that the request completed successfully * set up musb device address Now musb device should answer to this address From the host perspective, if peripheral device acquires SET_ADDRESS request, it now may be accessed only using that address. However, on heavy loaded systems, time between first and second musb ep0 interrupts may be too long and musb controller misses requests between. What is meant by heavily loaded system? Is the device is heavily loaded during enumeration stage? Why second ep0 interrupt is too long? whether interrupt occurrence to interrupt service is taking too long? I mean production system with aggressive power management and tens of interrupt sources. On such systems and in low CPU frequency case, you may meet condition when time between IRQ firing and ISR entering is increased in few times. In particular case of OMAP4 where I met this issue, time between first and second ep0 interrupt sometimes may be up to 800-900 uS and in this case the USB30CV test fails. If this time is 200-300 uS, the test successfully passes. Unfortunately, this time is not predictable and depends on many factors so this patch ensures we change the address as soon as sent ACK to the host. As result, device enumeration may be unsuccessful. This can be checked on USB3.0 Host and using USB3.0 test suite (from usb.org) running ch9 tests for USB2.0 devices. You mean the usb2.0 musb controller (in device mode) connected to USB3.0 host? Correct. USB2.0 musb controller in device mode, connected to USB3.0 host that runs USB30CV utility for USB2.0 devices Usually 'Addressed state/TD9.1: Device Descriptor Test' will fail The fix consists in checking CSR0L.DataEnd state and assigning the device address in the first ep0 interrupt handling, so delay is as minimal as possible Signed-off-by: Ruslan Bilovol ruslan.bilo...@ti.com --- drivers/usb/musb/musb_gadget_ep0.c | 31 +++ 1 file changed, 31 insertions(+) diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index c9c1ac4..59bc5a5 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -885,6 +885,37 @@ stall: finish: musb_writew(regs, MUSB_CSR0, musb-ackpend); + + /* + * If we are at end of SET_ADDRESS sequence, + * update the address immediately if possible, + * otherwise we may miss packets between + * sending ACK from musb side and musb's next + * interrupt handler firing (in which we update + * the address). At least this fixes next + * USB2.0 ch9 test of USB30CV utility: + * Addressed state - Device Descriptor test + */ + if (musb-set_address (musb-ackpend + MUSB_CSR0_P_DATAEND) + (musb-ep0_state == + MUSB_EP0_STAGE_STATUSIN)) { + u16 ack_delay = 500; + + while ((musb_readw(regs, MUSB_CSR0) + MUSB_CSR0_P_DATAEND) + --ack_delay) { + cpu_relax(); + udelay(1); + } + No need to loop here. It is self clearing bit. Yes, it is self-clearing bit and this is what we exactly use here. We are waiting for this bit self-clearing (that signalizes the end of Status Phase) or waiting for end of our timeout (when ack_delay == 0) + if (ack_delay) { + musb-set_address = false; + musb_writeb(mbase, MUSB_FADDR, + musb- address); + } Setting the address before status phase could lead to dropping of status packet(IN token) by controller, because the status phase is addressed to device with zero address
[PATCH] usb: musb: gadget: fix enumeration on heavy-loaded systems
From musb point of view, the Address Assignment sequence during device enumeration is next: - first ep0 interrupt: * read the address from USB_REQ_SET_ADDRESS request * set up CSR0L.DataEnd bit (that is ACK signalization for the host) - second ep0 interrupt: * indicates that the request completed successfully * set up musb device address Now musb device should answer to this address From the host perspective, if peripheral device acquires SET_ADDRESS request, it now may be accessed only using that address. However, on heavy loaded systems, time between first and second musb ep0 interrupts may be too long and musb controller misses requests between. As result, device enumeration may be unsuccessful. This can be checked on USB3.0 Host and using USB3.0 test suite (from usb.org) running ch9 tests for USB2.0 devices. Usually 'Addressed state/TD9.1: Device Descriptor Test' will fail The fix consists in checking CSR0L.DataEnd state and assigning the device address in the first ep0 interrupt handling, so delay is as minimal as possible Signed-off-by: Ruslan Bilovol ruslan.bilo...@ti.com --- drivers/usb/musb/musb_gadget_ep0.c | 31 +++ 1 file changed, 31 insertions(+) diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index c9c1ac4..59bc5a5 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -885,6 +885,37 @@ stall: finish: musb_writew(regs, MUSB_CSR0, musb-ackpend); + + /* +* If we are at end of SET_ADDRESS sequence, +* update the address immediately if possible, +* otherwise we may miss packets between +* sending ACK from musb side and musb's next +* interrupt handler firing (in which we update +* the address). At least this fixes next +* USB2.0 ch9 test of USB30CV utility: +* Addressed state - Device Descriptor test +*/ + if (musb-set_address (musb-ackpend + MUSB_CSR0_P_DATAEND) + (musb-ep0_state == + MUSB_EP0_STAGE_STATUSIN)) { + u16 ack_delay = 500; + + while ((musb_readw(regs, MUSB_CSR0) + MUSB_CSR0_P_DATAEND) + --ack_delay) { + cpu_relax(); + udelay(1); + } + + if (ack_delay) { + musb-set_address = false; + musb_writeb(mbase, MUSB_FADDR, + musb-address); + } + } + musb-ackpend = 0; } } -- 1.7.9.5 -- 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 v3 0/1] usb: musb: improve throughput in HOST mode
Hi guys, This is a resend (and v3) of my patch: http://permalink.gmane.org/gmane.linux.usb.general/67238 At this moment it has been successfully tested and used on top of 3.0 and 3.4 kernels on omap4 devices so it would be great to have it in upstream too. Regards, Ruslan v3: Implementation has been little bit changed to keep MUSB struct hc_driver as 'const' (as per Felipe's comments). Verified on top of 3.9-rc4. Ruslan Bilovol (1): usb: musb: implement (un)map_urb_for_dma hooks drivers/usb/musb/musb_host.c | 117 ++ 1 file changed, 117 insertions(+) -- 1.7.9.5 -- 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 v3 1/1] usb: musb: implement (un)map_urb_for_dma hooks
MUSB controller cannot work in DMA mode with misaligned buffers, switching in PIO mode. HCD core has hooks that allow to override the default DMA mapping and unmapping routines for host controllers that have special DMA requirements, such as alignment constraints. It is observed that work in PIO mode is slow and it's better to align buffers properly before passing them to MUSB This increased throughput 80-120 MBits/s over musb@omap4 with USB Gigabit Ethernet adapter attached. Some ideas are taken from ehci-tegra.c Signed-off-by: Ruslan Bilovol ruslan.bilo...@ti.com --- drivers/usb/musb/musb_host.c | 117 ++ 1 file changed, 117 insertions(+) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 1ce1fcf..33277c9 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2465,6 +2465,118 @@ static int musb_bus_resume(struct usb_hcd *hcd) return 0; } + +#ifndef CONFIG_MUSB_PIO_ONLY + +#define MUSB_USB_DMA_ALIGN 4 + +struct musb_temp_buffer { + void *kmalloc_ptr; + void *old_xfer_buffer; + u8 data[0]; +}; + +static void musb_free_temp_buffer(struct urb *urb) +{ + enum dma_data_direction dir; + struct musb_temp_buffer *temp; + + if (!(urb-transfer_flags URB_ALIGNED_TEMP_BUFFER)) + return; + + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + temp = container_of(urb-transfer_buffer, struct musb_temp_buffer, + data); + + if (dir == DMA_FROM_DEVICE) { + memcpy(temp-old_xfer_buffer, temp-data, + urb-transfer_buffer_length); + } + urb-transfer_buffer = temp-old_xfer_buffer; + kfree(temp-kmalloc_ptr); + + urb-transfer_flags = ~URB_ALIGNED_TEMP_BUFFER; +} + +static int musb_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) +{ + enum dma_data_direction dir; + struct musb_temp_buffer *temp; + void *kmalloc_ptr; + size_t kmalloc_size; + + if (urb-num_sgs || urb-sg || + urb-transfer_buffer_length == 0 || + !((uintptr_t)urb-transfer_buffer (MUSB_USB_DMA_ALIGN - 1))) + return 0; + + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + /* Allocate a buffer with enough padding for alignment */ + kmalloc_size = urb-transfer_buffer_length + + sizeof(struct musb_temp_buffer) + MUSB_USB_DMA_ALIGN - 1; + + kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); + if (!kmalloc_ptr) + return -ENOMEM; + + /* Position our struct temp_buffer such that data is aligned */ + temp = PTR_ALIGN(kmalloc_ptr, MUSB_USB_DMA_ALIGN); + + + temp-kmalloc_ptr = kmalloc_ptr; + temp-old_xfer_buffer = urb-transfer_buffer; + if (dir == DMA_TO_DEVICE) + memcpy(temp-data, urb-transfer_buffer, + urb-transfer_buffer_length); + urb-transfer_buffer = temp-data; + + urb-transfer_flags |= URB_ALIGNED_TEMP_BUFFER; + + return 0; +} + +static int musb_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) +{ + struct musb *musb = hcd_to_musb(hcd); + int ret; + + /* +* The DMA engine in RTL1.8 and above cannot handle +* DMA addresses that are not aligned to a 4 byte boundary. +* For such engine implemented (un)map_urb_for_dma hooks. +* Do not use these hooks for RTL1.8 +*/ + if (musb-hwvers MUSB_HWVERS_1800) + return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); + + ret = musb_alloc_temp_buffer(urb, mem_flags); + if (ret) + return ret; + + ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); + if (ret) + musb_free_temp_buffer(urb); + + return ret; +} + +static void musb_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + struct musb *musb = hcd_to_musb(hcd); + + usb_hcd_unmap_urb_for_dma(hcd, urb); + + /* Do not use this hook for RTL1.8 (see description above) */ + if (musb-hwvers MUSB_HWVERS_1800) + return; + + musb_free_temp_buffer(urb); +} +#endif /* !CONFIG_MUSB_PIO_ONLY */ + const struct hc_driver musb_hc_driver = { .description= musb-hcd, .product_desc = MUSB HDRC host driver, @@ -2484,6 +2596,11 @@ const struct hc_driver musb_hc_driver = { .urb_dequeue= musb_urb_dequeue, .endpoint_disable = musb_h_disable, +#ifndef CONFIG_MUSB_PIO_ONLY + .map_urb_for_dma= musb_map_urb_for_dma, + .unmap_urb_for_dma = musb_unmap_urb_for_dma, +#endif + .hub_status_data= musb_hub_status_data, .hub_control= musb_hub_control, .bus_suspend= musb_bus_suspend, -- 1.7.9.5 -- To unsubscribe from this list
Re: [PATCH RESEND v2 1/1] usb: musb: implement (un)map_urb_for_dma hooks
Hi Felipe, On Wed, Mar 27, 2013 at 3:17 PM, Felipe Balbi ba...@ti.com wrote: Hi, On Thu, Mar 14, 2013 at 08:12:09PM +0200, Ruslan Bilovol wrote: MUSB controller cannot work in DMA mode with misaligned buffers, switching in PIO mode. HCD core has hooks that allow to override the default DMA mapping and unmapping routines for host controllers that have special DMA requirements, such as alignment contraints. It is observed that work in PIO mode is slow and it's better to align buffers properly before passing them to MUSB This increased throughput 80-120 MBits/s over musb@omap4 with USB Gigabit ethernet adapter attached. Some ideas taken from ehci-tegra.c Signed-off-by: Ruslan Bilovol ruslan.bilo...@ti.com --- drivers/usb/musb/musb_core.c | 14 ++ drivers/usb/musb/musb_host.c | 102 +- drivers/usb/musb/musb_host.h |2 +- 3 files changed, 116 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 60b41cc..91ac166 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1431,6 +1431,20 @@ static int musb_core_init(u16 musb_type, struct musb *musb) /* log release info */ musb-hwvers = musb_read_hwvers(mbase); + +#ifndef CONFIG_MUSB_PIO_ONLY + /* + * The DMA engine in RTL1.8 and above cannot handle + * DMA addresses that are not aligned to a 4 byte boundary. + * For such engine implemented (un)map_urb_for_dma hooks. + * Do not use these hooks for RTL1.8 + */ + if (musb-hwvers MUSB_HWVERS_1800) { if you move this check to map/unmap and always return error if this is true, you can avoid removing 'const' from our struct hc_driver. Would that work ? If we return an error in map/unmap callbacks, this will break urb transferring, however I can call core function usb_hcd_(un)map_urb_for_dma() instead of returning the error (and that is default behavior if we do not have map/unmap callbacks set for the hc driver) so I can avoid removing 'const' from our struct hc_driver and this will work. The side effect will be only in small overhead for this path. So, will be this OK for you? I will send v3 in this case. -- Best regards, Ruslan Bilvol -- balbi -- 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 v2 0/1] omap usb host platform_data cleanup
Hello guys, This is v2 of my patch https://patchwork.kernel.org/patch/1232871/ rebased on v3.9-rc2. Removes deprecated flags and structures and saves few bytes of memory. Regards, Ruslan Ruslan Bilovol (1): omap: usb: host: remove deprecated flags and structures include/linux/platform_data/usb-omap.h | 20 1 file changed, 20 deletions(-) -- 1.7.9.5 -- 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 v2 1/1] omap: usb: host: remove deprecated flags and structures
These flags and structures are deprecated and there is no anymore users of them, so it's safe to remove them. Signed-off-by: Ruslan Bilovol ruslan.bilo...@ti.com --- include/linux/platform_data/usb-omap.h | 20 1 file changed, 20 deletions(-) diff --git a/include/linux/platform_data/usb-omap.h b/include/linux/platform_data/usb-omap.h index fa579b4..4c7acbe 100644 --- a/include/linux/platform_data/usb-omap.h +++ b/include/linux/platform_data/usb-omap.h @@ -38,34 +38,14 @@ enum usbhs_omap_port_mode { OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM }; -struct usbtll_omap_platform_data { - enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; -}; - -struct ehci_hcd_omap_platform_data { - enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; - int reset_gpio_port[OMAP3_HS_USB_PORTS]; - struct regulator*regulator[OMAP3_HS_USB_PORTS]; - unsignedphy_reset:1; -}; - -struct ohci_hcd_omap_platform_data { - enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; - unsignedes2_compatibility:1; -}; - struct usbhs_omap_platform_data { int nports; enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; int reset_gpio_port[OMAP3_HS_USB_PORTS]; struct regulator*regulator[OMAP3_HS_USB_PORTS]; - struct ehci_hcd_omap_platform_data *ehci_data; - struct ohci_hcd_omap_platform_data *ohci_data; - /* OMAP3 = ES2.1 have a single ulpi bypass control bit */ unsigned single_ulpi_bypass:1; - unsigned es2_compatibility:1; unsigned phy_reset:1; }; -- 1.7.9.5 -- 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 RESEND v2 0/1] usb: musb: improve throughput in HOST mode
Hi guys, This is a resend of my patch: http://permalink.gmane.org/gmane.linux.usb.general/67238 At this moment it has been successfully tested and used on top of 3.0 and 3.4 kernels on omap4 devices so it would be great to have it in upstream too. Regards, Ruslan Ruslan Bilovol (1): usb: musb: implement (un)map_urb_for_dma hooks drivers/usb/musb/musb_core.c | 14 ++ drivers/usb/musb/musb_host.c | 102 +- drivers/usb/musb/musb_host.h |2 +- 3 files changed, 116 insertions(+), 2 deletions(-) -- 1.7.9.5 -- 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