Re: [PATCH v2] usb: cdc-wdm: Add device-id for Huawei 3G/LTE modems

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 2012-01-23 at 21:31 +0100, Bjørn Mork wrote:
> Dan Williams <dcbw@xxxxxxxxxx> writes:
> 
> > On Mon, 2012-01-23 at 19:56 +0100, Bjørn Mork wrote:
> >> Dan Williams <dcbw@xxxxxxxxxx> writes:
> >> 
> >> > So the Pantech UML290 has the following layout:
> >> >
> >> > 0 (2/2/1):    CDC-ACM for AT commands
> >> > 1 (10/0/0):   CDC-DATA for interface 0
> >> > 2 (ff/ff/ff): Qualcomm DIAG
> >> > 3 (ff/fd/ff): NMEA
> >> > 4 (ff/fe/ff): Pantech WMC
> >> > 5 (ff/f0/ff): RMNET/QMI port
> >> 
> >> I assume this is after som modeswitch command?  The same as the Windows
> >> driver uses?  And you don't know if there are other options?
> >
> > The UML290 does not require modeswitching at all.
> 
> OK, nice.
> 
> >> > Interface 5 is obviously the one we want here.  And the WDM driver is
> >> > only looking for certain descriptors.  Do we hack CDC-WDM and qmi_wwan
> >> > up for these types of devices?
> >> 
> >> 
> >> Interface 5 has three endpoints?  Bulk in/out and interrupt in?
> >
> > Yes, three endpoints like you describe.
> >
> >> OK, this is where the fun begins.  I knew there was some reason why I
> >> was struggling with the interface sharing...  I guess we cannot expect
> >> every vendor to provide a "Linux mode" with two separate interfaces for
> >> the RMNET/QMI port.
> >> 
> >> > Second, on Gobi devices, we have four USB interfaces, all FF/FF/FF.
> >> > Intf 0 and 2 have interrupt endpoints.  One of them is a DIAG interface,
> >> > one is NMEA, and the other two are AT and RMNET/QMI.
> >> 
> >> What kind of endpoints are on the RMNET/QMI interface?
> >
> > see Elly's cleaned up Gobi driver here: http://lwn.net/Articles/439173/
> > as it has the logic to set everything up for Gobi devices.  I expect
> > that it would work with the UML290 as well if things were hacked up a
> > bit.  It should be pretty clear here how to talk to them.
> >
> > In short we have:
> >
> > 0: (ff/ff/ff) (in/out/interrupt) - rmnet/QMI
> > 1: (ff/ff/ff) (in/out) - DIAG
> > 2: (ff/ff/ff) (in/out) - AT commands & PPP
> > 3: (ff/ff/ff) (in/out/interrupt) - NMEA (?)
> >
> > lsusb attached for both a Gobi 2K device and the UML290.
> >
> >> If you have these devices, then it would be useful to verify that the
> >> cdc-wdm driver can be used to provide access to QMI without any further
> >> changes.  This should in theory just work if you unload any other
> >> drivers binding to the RMNET/QMI interface, and bind cdc-wdm to it
> >> instead.  This requires that you have the minimum buffer size patch
> >> installed, but should not require any other changes.
> >
> > I tried that quickly but of course the WDM driver fails with EINVAL
> > because there are 3 endpoints on the RMNET/QMI interface (bulk
> > in/out/interrupt) instead of the 1 expected:
> >
> > 	rv = -EINVAL;
> > 	iface = intf->cur_altsetting;
> > 	if (iface->desc.bNumEndpoints != 1)
> > 		goto err;
> >
> > I briefly thought about hacking it to find the interrupt endpoing, but
> > if the cdc-wdm driver apparently only cares about 1 endpoint there's not
> > much point to handing it an interface with 3 I don't think...
> 
> Right, forgot about that part.  You could hack it so that it was happily
> ignoring the extra bulk endpoints as long as it found an interrupt
> endpoint. 
> 
> 
> >> > I think so far the Huawei device is the only one that I've seen that
> >> > exposes descriptors that are quasi-CDC at all.  How should we handle the
> >> > rest of these?
> >> 
> >> Good question.  Guess I'm going to see if I can make qmi_wwan and
> >> cdc-wdm share an interface after all.
> >
> > Also you may not have seen, but the QUIC codeaurora people pushed a new
> > rmnet USB driver to their MSM kernel tree:
> >
> > https://www.codeaurora.org/gitweb/quic/le/?p=kernel/msm.git;a=commit;h=37c35e4ee5226099374a1a1eda637d0f26fc023d
> 
> Thanks for the pointer.  Will take a look at it.  But I guess these are
> still doing the integrated QMI approach.  Which most likely isn't
> acceptable to anyone here, after you managed to convince me :-)
> 
> > In the end, if the Huawei device mostly presents itself as WDM, and
> > other Gobi/MSM8xxx/MSM9xxx devices present themselves like Gobi cards
> > do, perhaps we should have separate drivers?  Does it make sense to keep
> > hacking up CDC-WDM for devices that are clearly not exposed that way,
> > even if the internal operation would be similar?  Also in the end they
> > are all just character devices to talk QMI so it doesn't really matter
> > what driver exposes that interface.  It would be nice to share if we
> > can, but making too many changes to WDM probably isn't the right
> > approach either.
> 
> That is for Oliver to decide I guess.  
> 
> But I believe it can make sense to reuse the cdc-wdm driver, even if it
> needs some small changes to allow other drivers to call it.  The actual
> work it does is pretty standalone: Listen on the interrupt ep, send
> control messages and do file operations on the char device.  Provided
> the other netdev drivers don't need notifications, then this can all be
> done without them being involved at all.  The only issues are
> register/deregister instead of probe/disconnect, and doing the mapping
> to the device specific struct.  
> 
> And having all these devices expose their QMI interface as a
> /dev/cdc-wdmX should make things look more consistent for users and
> userspace.

The following patch to cdc-wdm allows me to talk to the UML290 with QMI.
Quite straightforward, just find the interrupt endpoint like you said.
Any comments on it, or should I submit as a format patch?

One oddity is that cdc-wdm seems to be looking at interfaces 3 and 4
too, but it shouldn't because the device list says to look only at
interface 5 (ff/f0/ff).  Any idea why that's happening?  3 and 4 should
be driven by 'qcaux' not cdc-wdm.

[ 5524.707877] cdc_acm 2-1:1.0: ttyACM0: USB ACM device
[ 5524.708969] qcaux 2-1:1.2: qcaux converter detected
[ 5524.709205] usb 2-1: qcaux converter now attached to ttyUSB1
[ 5524.709346] cdc_wdm 2-1:1.3: failed to find interrupt endpoint
[ 5524.709356] cdc_wdm: probe of 2-1:1.3 failed with error -22
[ 5524.709484] cdc_wdm 2-1:1.4: failed to find interrupt endpoint
[ 5524.709493] cdc_wdm: probe of 2-1:1.4 failed with error -22
[ 5524.709793] cdc_wdm 2-1:1.5: cdc-wdm0: USB WDM device

Dan

diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index efe6849..f5b07e7 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -38,6 +47,15 @@ static const struct usb_device_id wdm_ids[] = {
 		.bInterfaceClass = USB_CLASS_COMM,
 		.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
 	},
+        {
+               .match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT,
+                                       USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = 0x106c,
+               .idProduct          = 0x3718,
+               .bInterfaceClass    = 0xFF,
+               .bInterfaceSubClass = 0xF0,
+               .bInterfaceProtocol = 0xFF
+       },
 	{ }
 };
 
@@ -626,11 +652,12 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct wdm_device *desc;
 	struct usb_host_interface *iface;
-	struct usb_endpoint_descriptor *ep;
+	struct usb_endpoint_descriptor *ep = NULL, *tmpep;
 	struct usb_cdc_dmm_desc *dmhd;
 	u8 *buffer = intf->altsetting->extra;
 	int buflen = intf->altsetting->extralen;
 	u16 maxcom = WDM_DEFAULT_BUFSIZE;
+	int i;
 
 	if (!buffer)
 		goto out;
@@ -661,6 +688,22 @@ next_desc:
 		buffer += buffer[0];
 	}
 
+	/* Find the interrupt endpoint */
+	rv = -EINVAL;
+	iface = intf->cur_altsetting;
+	for (i = 0; i < iface->desc.bNumEndpoints; i++) {
+		tmpep = &iface->endpoint[i].desc;
+		if (tmpep && usb_endpoint_is_int_in (tmpep)) {
+			ep = tmpep;
+			break;
+		}
+	}
+
+	if (!ep) {
+		dev_dbg(&intf->dev, "failed to find interrupt endpoint\n");
+		goto out;
+	}
+
 	rv = -ENOMEM;
 	desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
 	if (!desc)
@@ -674,13 +717,6 @@ next_desc:
 	desc->intf = intf;
 	INIT_WORK(&desc->rxwork, wdm_rxwork);
 
-	rv = -EINVAL;
-	iface = intf->cur_altsetting;
-	if (iface->desc.bNumEndpoints != 1)
-		goto err;
-	ep = &iface->endpoint[0].desc;
-	if (!ep || !usb_endpoint_is_int_in(ep))
-		goto err;
 
	desc->wMaxPacketSize = usb_endpoint_maxp(ep);
 	desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;


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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux