Userspace applications need to know the maximum supported message
size.

Using a character device as interface to USB control messages hides
the fact that these messages have a strict size limit.  The userspace
application must in most cases still be aware of this limit. It must
allocate sufficiently large read buffers, and it must prevent the
driver from splitting messages if the protocol requires more
advanced fragmentation like e.g. CDC MBIM does.

The limit could be read from CDC functional descriptors for CDC WDM
and CDC MBIM devices, duplicating the parsing already done by the
driver probe.  For other devices, where the limit is based on a
hardcoded default, the application will need hardcode this default
as well. Such hidden and implicit kernel dependencies are bad and
makes it impossible to ever change the defaults.

All this is unnecessarily complex and likely to make drivers and
applications end up using different limits, causing errors which
are hard to debug and replicate.

Exporting the maximum message size from the driver simplifies
the task for the userspace application, and creates a unified
information source independent of device and function class.

Signed-off-by: Bjørn Mork <bj...@mork.no>
---

Oliver Neukum <oli...@neukum.org> writes:
> On Saturday 09 February 2013 20:16:20 Bjørn Mork wrote:
>> Oliver Neukum <oli...@neukum.org> writes:
>> > On Saturday 09 February 2013 18:41:52 Bjørn Mork wrote:
>
>> Well, OK..., "generic" then.  In the sense that the attribute stays the
>> same regardless of whether the value is hardcoded in the driver (QMI),
>> or parsed from wMaxCommand (CDC WDM) or wMaxControlMessage (CDC MBIM)
>> 
>> Not sure I understand what you want here...  I am trying to avoid having
>> three different attributes for the three drivers currently needing this
>> number.
>
> I would say that the most generic solution would be an ioctl()

I am not exactly sure how to do this, but does this look like something
that could be submitted?

The issue just came up again, after I tried to get a user with an
Ericsson H5521gw modem to run mbimcli.  It failed because the hard coded
message size is too big. We need a simple way for userspace applications
to check the message size.


Bjørn

 Documentation/ioctl/ioctl-number.txt |    1 +
 drivers/usb/class/cdc-wdm.c          |   19 +++++++++++++++++++
 include/linux/usb/cdc-wdm.h          |    2 ++
 include/uapi/linux/usb/cdc-wdm.h     |   21 +++++++++++++++++++++
 4 files changed, 43 insertions(+)
 create mode 100644 include/uapi/linux/usb/cdc-wdm.h

diff --git a/Documentation/ioctl/ioctl-number.txt 
b/Documentation/ioctl/ioctl-number.txt
index 3210540..237acab 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -131,6 +131,7 @@ Code  Seq#(hex)     Include File            Comments
 'H'    40-4F   sound/hdspm.h           conflict!
 'H'    40-4F   sound/hdsp.h            conflict!
 'H'    90      sound/usb/usx2y/usb_stream.h
+'H'    A0      uapi/linux/usb/cdc-wdm.h
 'H'    C0-F0   net/bluetooth/hci.h     conflict!
 'H'    C0-DF   net/bluetooth/hidp/hidp.h       conflict!
 'H'    C0-DF   net/bluetooth/cmtp/cmtp.h       conflict!
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 5f0cb41..6463d8c 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -13,6 +13,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/ioctl.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
@@ -628,6 +629,22 @@ static int wdm_release(struct inode *inode, struct file 
*file)
        return 0;
 }
 
+static long wdm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct wdm_device *desc = file->private_data;
+       int rv = 0;
+
+       switch (cmd) {
+       case IOCTL_WDM_MAX_COMMAND:
+               if (copy_to_user((void __user *)arg, &desc->wMaxCommand, 
sizeof(desc->wMaxCommand)))
+                       rv = -EFAULT;
+               break;
+       default:
+               rv = -ENOTTY;
+       }
+       return rv;
+}
+
 static const struct file_operations wdm_fops = {
        .owner =        THIS_MODULE,
        .read =         wdm_read,
@@ -636,6 +653,8 @@ static const struct file_operations wdm_fops = {
        .flush =        wdm_flush,
        .release =      wdm_release,
        .poll =         wdm_poll,
+       .unlocked_ioctl = wdm_ioctl,
+       .compat_ioctl = wdm_ioctl,
        .llseek =       noop_llseek,
 };
 
diff --git a/include/linux/usb/cdc-wdm.h b/include/linux/usb/cdc-wdm.h
index 719c332..0b3f429 100644
--- a/include/linux/usb/cdc-wdm.h
+++ b/include/linux/usb/cdc-wdm.h
@@ -11,6 +11,8 @@
 #ifndef __LINUX_USB_CDC_WDM_H
 #define __LINUX_USB_CDC_WDM_H
 
+#include <uapi/linux/usb/cdc-wdm.h>
+
 extern struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
                                        struct usb_endpoint_descriptor *ep,
                                        int bufsize,
diff --git a/include/uapi/linux/usb/cdc-wdm.h b/include/uapi/linux/usb/cdc-wdm.h
new file mode 100644
index 0000000..f03134f
--- /dev/null
+++ b/include/uapi/linux/usb/cdc-wdm.h
@@ -0,0 +1,21 @@
+/*
+ * USB CDC Device Management userspace API definitions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _UAPI__LINUX_USB_CDC_WDM_H
+#define _UAPI__LINUX_USB_CDC_WDM_H
+
+/*
+ * This IOCTL is used to retrieve the wMaxCommand for the device,
+ * defining the message limit for both reading and writing.
+ *
+ * For CDC WDM functions this will be the wMaxCommand field of the
+ * Device Management Functional Descriptor.
+ */
+#define IOCTL_WDM_MAX_COMMAND _IOR('H', 0xA0, __u16)
+
+#endif /* _UAPI__LINUX_USB_CDC_WDM_H */
-- 
1.7.10.4

--
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

Reply via email to