Hi David, hi listmembers,
your suggestion was wise. Here's a preliminary version of a
patch to rewrite of cdc-acm's probe properly evaluating the
union descriptor.
Cheers to Steve, whose box I crashed writing this.
Regards
Oliver
You can import this changeset into BK by piping this whole message to:
'| bk receive [path to repository]' or apply the patch as usual.
===================================================================
[EMAIL PROTECTED], 2004-04-23 00:59:50+02:00, [EMAIL PROTECTED]
-rewrite probe of cdc-acm to properly evaluate the union descriptor
cdc-acm.c | 342 ++++++++++++++++++++++++--------------------------------------
cdc-acm.h | 114 ++++++++++++++++++++
2 files changed, 247 insertions(+), 209 deletions(-)
diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
--- a/drivers/usb/class/cdc-acm.c Fri Apr 23 01:02:07 2004
+++ b/drivers/usb/class/cdc-acm.c Fri Apr 23 01:02:07 2004
@@ -60,6 +60,8 @@
#include <linux/usb.h>
#include <asm/byteorder.h>
+#include "cdc-acm.h"
+
/*
* Version Information
*/
@@ -67,98 +69,6 @@
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik"
#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN
adapters"
-/*
- * CMSPAR, some architectures can't have space and mark parity.
- */
-
-#ifndef CMSPAR
-#define CMSPAR 0
-#endif
-
-/*
- * Major and minor numbers.
- */
-
-#define ACM_TTY_MAJOR 166
-#define ACM_TTY_MINORS 32
-
-/*
- * Requests.
- */
-
-#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
-
-#define ACM_REQ_COMMAND 0x00
-#define ACM_REQ_RESPONSE 0x01
-#define ACM_REQ_SET_FEATURE 0x02
-#define ACM_REQ_GET_FEATURE 0x03
-#define ACM_REQ_CLEAR_FEATURE 0x04
-
-#define ACM_REQ_SET_LINE 0x20
-#define ACM_REQ_GET_LINE 0x21
-#define ACM_REQ_SET_CONTROL 0x22
-#define ACM_REQ_SEND_BREAK 0x23
-
-/*
- * IRQs.
- */
-
-#define ACM_IRQ_NETWORK 0x00
-#define ACM_IRQ_LINE_STATE 0x20
-
-/*
- * Output control lines.
- */
-
-#define ACM_CTRL_DTR 0x01
-#define ACM_CTRL_RTS 0x02
-
-/*
- * Input control lines and line errors.
- */
-
-#define ACM_CTRL_DCD 0x01
-#define ACM_CTRL_DSR 0x02
-#define ACM_CTRL_BRK 0x04
-#define ACM_CTRL_RI 0x08
-
-#define ACM_CTRL_FRAMING 0x10
-#define ACM_CTRL_PARITY 0x20
-#define ACM_CTRL_OVERRUN 0x40
-
-/*
- * Line speed and caracter encoding.
- */
-
-struct acm_line {
- __u32 speed;
- __u8 stopbits;
- __u8 parity;
- __u8 databits;
-} __attribute__ ((packed));
-
-/*
- * Internal driver structures.
- */
-
-struct acm {
- struct usb_device *dev; /* the corresponding usb
device */
- struct usb_interface *control; /* control interface */
- struct usb_interface *data; /* data interface */
- struct tty_struct *tty; /* the corresponding tty */
- struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
- struct acm_line line; /* line coding (bits, stop,
parity) */
- struct work_struct work; /* work queue entry for line
discipline waking up */
- struct tasklet_struct bh; /* rx processing */
- unsigned int ctrlin; /* input control lines (DCD,
DSR, RI, break, overruns) */
- unsigned int ctrlout; /* output control lines (DTR,
RTS) */
- unsigned int writesize; /* max packet size for the
output bulk endpoint */
- unsigned int used; /* someone has this acm's
device open */
- unsigned int minor; /* acm minor number */
- unsigned char throttle; /* throttled by tty layer */
- unsigned char clocal; /* termios CLOCAL */
-};
-
static struct usb_driver acm_driver;
static struct tty_driver *acm_tty_driver;
static struct acm *acm_table[ACM_TTY_MINORS];
@@ -570,142 +480,156 @@
static int acm_probe (struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct usb_device *dev;
- struct acm *acm;
- struct usb_host_config *cfacm;
- struct usb_interface *data;
- struct usb_host_interface *ifcom, *ifdata;
+ struct union_desc *union_header = NULL;
+ char *buffer = intf->altsetting->extra;
+ int buflen = intf->altsetting->extralen;
+ struct usb_interface *control_interface;
+ struct usb_interface *data_interface;
struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
- int readsize, ctrlsize, minor, j;
- unsigned char *buf;
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct acm *acm;
+ int minor;
+ int ctrlsize,readsize;
+ char *buf;
- dev = interface_to_usbdev (intf);
+ if (!buffer) {
+ err("Wierd descriptor references");
+ return -EINVAL;
+ }
- cfacm = dev->actconfig;
+ while (buflen > 0) {
+ if (buffer [1] != USB_DT_CS_INTERFACE) {
+ err("skipping garbage");
+ goto next_desc;
+ }
- for (j = 0; j < cfacm->desc.bNumInterfaces - 1; j++) {
-
- if (usb_interface_claimed(cfacm->interface[j]) ||
- usb_interface_claimed(cfacm->interface[j + 1]))
- continue;
-
- /* We know we're probe()d with the control interface.
- * FIXME ACM doesn't guarantee the data interface is
- * adjacent to the control interface, or that if one
- * is there it's not for call management ... so use
- * the cdc union descriptor whenever there is one.
- */
- ifcom = intf->cur_altsetting;
- if (intf == cfacm->interface[j]) {
- ifdata = cfacm->interface[j + 1]->cur_altsetting;
- data = cfacm->interface[j + 1];
- } else if (intf == cfacm->interface[j + 1]) {
- ifdata = cfacm->interface[j]->cur_altsetting;
- data = cfacm->interface[j];
- } else
- continue;
-
- if (ifdata->desc.bInterfaceClass != 10 ||
ifdata->desc.bNumEndpoints < 2)
- continue;
-
- epctrl = &ifcom->endpoint[0].desc;
- epread = &ifdata->endpoint[0].desc;
- epwrite = &ifdata->endpoint[1].desc;
-
- if ((epctrl->bEndpointAddress & 0x80) != 0x80 ||
(epctrl->bmAttributes & 3) != 3 ||
- (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes &
3) != 2 ||
- ((epread->bEndpointAddress & 0x80) ^
(epwrite->bEndpointAddress & 0x80)) != 0x80)
- continue;
-
- if ((epread->bEndpointAddress & 0x80) != 0x80) {
- epread = &ifdata->endpoint[1].desc;
- epwrite = &ifdata->endpoint[0].desc;
+ switch (buffer [2]) {
+ case CDC_UNION_TYPE: /* we've found it */
+ if (union_header) {
+ err("More than one union descriptor, skipping
...");
+ goto next_desc;
+ }
+ union_header = (struct union_desc *)buffer;
+ break;
+ default:
+ err("Ignoring extra header");
+ break;
}
+next_desc:
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
- for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor];
minor++);
- if (acm_table[minor]) {
- err("no more free acm devices");
- return -ENODEV;
- }
+ if (!union_header) {
+ err("No union descriptor, giving up");
+ return -ENODEV;
+ }
- if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
- err("out of memory");
- return -ENOMEM;
- }
- memset(acm, 0, sizeof(struct acm));
+ control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
+ data_interface = usb_ifnum_to_if(usb_dev, union_header->bSlaveInterface0);
+ if (!control_interface || !data_interface) {
+ err("no interfaces");
+ return -ENODEV;
+ }
- ctrlsize = epctrl->wMaxPacketSize;
- readsize = epread->wMaxPacketSize;
- acm->writesize = epwrite->wMaxPacketSize;
- acm->control = intf;
- acm->data = data;
- acm->minor = minor;
- acm->dev = dev;
-
- acm->bh.func = acm_rx_tasklet;
- acm->bh.data = (unsigned long) acm;
- INIT_WORK(&acm->work, acm_softint, acm);
-
- if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize,
GFP_KERNEL))) {
- err("out of memory");
- kfree(acm);
- return -ENOMEM;
- }
+ if (usb_interface_claimed(data_interface)) { /* valid in this context */
+ err("The data interface isn't available");
+ return -EBUSY;
+ }
- acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
- if (!acm->ctrlurb) {
- err("out of memory");
- kfree(acm);
- kfree(buf);
- return -ENOMEM;
- }
- acm->readurb = usb_alloc_urb(0, GFP_KERNEL);
- if (!acm->readurb) {
- err("out of memory");
- usb_free_urb(acm->ctrlurb);
- kfree(acm);
- kfree(buf);
- return -ENOMEM;
- }
- acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
- if (!acm->writeurb) {
- err("out of memory");
- usb_free_urb(acm->readurb);
- usb_free_urb(acm->ctrlurb);
- kfree(acm);
- kfree(buf);
- return -ENOMEM;
- }
+ if (data_interface->cur_altsetting->desc.bInterfaceClass !=
CDC_DATA_INTERFACE_TYPE)
+ return -EINVAL;
+ if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
+ return -EINVAL;
- usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev,
epctrl->bEndpointAddress),
- buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
+ epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
+ epread = &data_interface->cur_altsetting->endpoint[0].desc;
+ epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
+
+ dbg("interfaces are valid");
+ for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
+
+ if (acm_table[minor]) {
+ err("no more free acm devices");
+ return -ENODEV;
+ }
- usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev,
epread->bEndpointAddress),
- buf += ctrlsize, readsize, acm_read_bulk, acm);
- acm->readurb->transfer_flags |= URB_NO_FSBR;
+ if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
+ err("out of memory");
+ return -ENOMEM;
+ }
+ memset(acm, 0, sizeof(struct acm));
- usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev,
epwrite->bEndpointAddress),
- buf += readsize, acm->writesize, acm_write_bulk, acm);
- acm->writeurb->transfer_flags |= URB_NO_FSBR;
+ ctrlsize = epctrl->wMaxPacketSize;
+ readsize = epread->wMaxPacketSize;
+ acm->writesize = epwrite->wMaxPacketSize;
+ acm->control = control_interface;
+ acm->data = data_interface;
+ acm->minor = minor;
+ acm->dev = usb_dev;
+
+ acm->bh.func = acm_rx_tasklet;
+ acm->bh.data = (unsigned long) acm;
+ INIT_WORK(&acm->work, acm_softint, acm);
+
+
+ if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
+ err("out of memory");
+ kfree(acm);
+ return -ENOMEM;
+ }
- dev_info(&intf->dev, "ttyACM%d: USB ACM device", minor);
+ acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!acm->ctrlurb) {
+ err("out of memory");
+ kfree(acm);
+ kfree(buf);
+ return -ENOMEM;
+ }
+ acm->readurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!acm->readurb) {
+ err("out of memory");
+ usb_free_urb(acm->ctrlurb);
+ kfree(acm);
+ kfree(buf);
+ return -ENOMEM;
+ }
+ acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!acm->writeurb) {
+ err("out of memory");
+ usb_free_urb(acm->readurb);
+ usb_free_urb(acm->ctrlurb);
+ kfree(acm);
+ kfree(buf);
+ return -ENOMEM;
+ }
- acm_set_control(acm, acm->ctrlout);
+ usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev,
epctrl->bEndpointAddress),
+ buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
- acm->line.speed = cpu_to_le32(9600);
- acm->line.databits = 8;
- acm_set_line(acm, &acm->line);
+ usb_fill_bulk_urb(acm->readurb, usb_dev, usb_rcvbulkpipe(usb_dev,
epread->bEndpointAddress),
+ buf += ctrlsize, readsize, acm_read_bulk, acm);
+ acm->readurb->transfer_flags |= URB_NO_FSBR;
- usb_driver_claim_interface(&acm_driver, data, acm);
+ usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev,
epwrite->bEndpointAddress),
+ buf += readsize, acm->writesize, acm_write_bulk, acm);
+ acm->writeurb->transfer_flags |= URB_NO_FSBR;
- tty_register_device(acm_tty_driver, minor, &intf->dev);
+ dev_info(&intf->dev, "ttyACM%d: USB ACM device", minor);
- acm_table[minor] = acm;
- usb_set_intfdata (intf, acm);
- return 0;
- }
+ acm_set_control(acm, acm->ctrlout);
+
+ acm->line.speed = cpu_to_le32(9600);
+ acm->line.databits = 8;
+ acm_set_line(acm, &acm->line);
- return -EIO;
+ usb_driver_claim_interface(&acm_driver, data_interface, acm);
+
+ tty_register_device(acm_tty_driver, minor, &intf->dev);
+
+ acm_table[minor] = acm;
+ usb_set_intfdata (intf, acm);
+ return 0;
}
static void acm_disconnect(struct usb_interface *intf)
diff -Nru a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/class/cdc-acm.h Fri Apr 23 01:02:07 2004
@@ -0,0 +1,114 @@
+/*
+ *
+ * Includes for cdc-acm.c
+ *
+ * Mainly take from usbnet's cdc-ether part
+ *
+ */
+
+/*
+ * CMSPAR, some architectures can't have space and mark parity.
+ */
+
+#ifndef CMSPAR
+#define CMSPAR 0
+#endif
+
+/*
+ * Major and minor numbers.
+ */
+
+#define ACM_TTY_MAJOR 166
+#define ACM_TTY_MINORS 32
+
+/*
+ * Requests.
+ */
+
+#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+
+#define ACM_REQ_COMMAND 0x00
+#define ACM_REQ_RESPONSE 0x01
+#define ACM_REQ_SET_FEATURE 0x02
+#define ACM_REQ_GET_FEATURE 0x03
+#define ACM_REQ_CLEAR_FEATURE 0x04
+
+#define ACM_REQ_SET_LINE 0x20
+#define ACM_REQ_GET_LINE 0x21
+#define ACM_REQ_SET_CONTROL 0x22
+#define ACM_REQ_SEND_BREAK 0x23
+
+/*
+ * IRQs.
+ */
+
+#define ACM_IRQ_NETWORK 0x00
+#define ACM_IRQ_LINE_STATE 0x20
+
+/*
+ * Output control lines.
+ */
+
+#define ACM_CTRL_DTR 0x01
+#define ACM_CTRL_RTS 0x02
+
+/*
+ * Input control lines and line errors.
+ */
+
+#define ACM_CTRL_DCD 0x01
+#define ACM_CTRL_DSR 0x02
+#define ACM_CTRL_BRK 0x04
+#define ACM_CTRL_RI 0x08
+
+#define ACM_CTRL_FRAMING 0x10
+#define ACM_CTRL_PARITY 0x20
+#define ACM_CTRL_OVERRUN 0x40
+
+/*
+ * Line speed and caracter encoding.
+ */
+
+struct acm_line {
+ __u32 speed;
+ __u8 stopbits;
+ __u8 parity;
+ __u8 databits;
+} __attribute__ ((packed));
+
+/*
+ * Internal driver structures.
+ */
+
+struct acm {
+ struct usb_device *dev; /* the corresponding usb
device */
+ struct usb_interface *control; /* control interface */
+ struct usb_interface *data; /* data interface */
+ struct tty_struct *tty; /* the corresponding tty */
+ struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
+ struct acm_line line; /* line coding (bits, stop,
parity) */
+ struct work_struct work; /* work queue entry for line
discipline waking up */
+ struct tasklet_struct bh; /* rx processing */
+ unsigned int ctrlin; /* input control lines (DCD,
DSR, RI, break, overruns) */
+ unsigned int ctrlout; /* output control lines (DTR,
RTS) */
+ unsigned int writesize; /* max packet size for the
output bulk endpoint */
+ unsigned int used; /* someone has this acm's
device open */
+ unsigned int minor; /* acm minor number */
+ unsigned char throttle; /* throttled by tty layer */
+ unsigned char clocal; /* termios CLOCAL */
+};
+
+/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
+struct union_desc {
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bDescriptorSubType;
+
+ u8 bMasterInterface0;
+ u8 bSlaveInterface0;
+ /* ... and there could be other slave interfaces */
+} __attribute__ ((packed));
+
+#define CDC_UNION_TYPE 0x06
+#define CDC_DATA_INTERFACE_TYPE 0x0a
+
===================================================================
This BitKeeper patch contains the following changesets:
1.1927
## Wrapped with gzip_uu ##
begin 664 bkpatch12874
M'XL(`.].B$```[T::7/:2/8S_(H>IS8#-L8Z.,W8%0PXR\8&C\"92652*B&U
M0&LA,5++QR[SW_>];DD(A)TX-5G;!7V\?O?5G;[EMAIL PROTECTED]/B&_-,/
M&4RIYWNTNO"7U'6\Z+'J!W/8U'P?-D]P^42<.)D&E(8G"!0J]2+`W!C,7!#8
M"D\+<E5-5]C3BIX6M,'[VZNN5BR>G9'>PO#F=$(9.3LK,C^X-UPK?&>PA>M[
M51887KBDS*B:[EMAIL PROTECTED]@MRXW5:G>6,L-J=9<F[(ERT9-II:DU%J-V@;;
M:F6VFU+5#RT79=A&5)-JBJRHBJHVUW"P+17[1*[*;:5)I-H)_"DJD:33>ONT
M+AU)RJDD$2'UNWWZ(4<*.9:*%^3O%:57-,EQ0!\"AU&R"OP9);Y-3,L\-LPE
MT,*U%0W<)T*!:F0`%%M0$GF.[Q&+AF;@K("CX@<B-UI*HWBST7OQ^)4_Q:)D
M2,[EMAIL PROTECTED]<"T^B<'9BND88GL2\5A>)SN&G+M>5M5('#:Q-HV8H=GM6I[)-
MP0I_#W9U+<GU9AV8?=D<682(QLR8I2;)S76]T6PWUC-3K=NR;"LUU59I<_:=
M3)I9)M6:[EMAIL PROTECTED]'5&L\&EZ0#.-C1!^([;CT]"7`XD<"R'ZH=7B(2-OQ(9_6E6^)
M#^E'Q(=)[EMAIL PROTECTED](`:[EMAIL PROTECTED])=1\(%QCBXR4HC>04\CN1'EN*_!W!]'^P
ME/Q]EI+EVH_)99=$QDR$D3F&M/;`_T`7+VO]]:[EMAIL PROTECTED])X<[EMAIL PROTECTED]:%GNA%D
M0V+[`4FC,=Z\-AP/\B<S[BBQ`W])@`>/LI]##DDAG09D901,@)\4_Q!X2>]Z
M<M/5*B0$Y1$C,!>0HDT6!4#&-+R?&5D8]Y2$*\.$;<\B2R.X0T0.>ZK&B-XX
MMF=1.T95?`-CQZ/QM%`H2,4WU+,<.Z5Y;?P;).#8'`]&7K2<@=I2?#&";N]:
MGTX_Z=?=?XT!C]QHY+>&H[$V*114)46NT3\C&K(<MMO)A:Y-=3A9*)1P,OUT
M,]![5]W)A*S%[J`WO-&'H^E`N^SV!N4=5K3!KWIO?'W='?5!ID=)[EMAIL PROTECTED]
M>#09X*Z<VYT,[EMAIL PROTECTED]@YJE?#;I:%J2VAT4D<S4<X;Z29_%]
M9G<_B[WQ:[EMAIL PROTECTED])D,[EMAIL PROTECTED]'WU53I0^W7O>:#=7TTF/XVUC[LT1GN
M(C/[EMAIL PROTECTED]&,<16T6,F+['`M\E$-=T+X7>5+O2^U.MD%<ZW]*FDX)0=\JK
MET/,?1%'A`:!O]\3!:%>_SE"_8E6R-N5;UW$TM?VL#?D.ZU]Q"ZU+OCW>]B7
MI?PNQ-9P^JF0-S/?'7\<:-KM"'9K&YU>(4BXHM3B`IM&8)@,[EMAIL PROTECTED]'DB
M=LB"R&0$THO.E?+?8D'7(U419SM\UB(A\U<SAX7)7"2%9&89S!"[EMAIL PROTECTED]
[EMAIL PROTECTED];`AV>X<08E@@/,0GF>D)UX!CE.M^B]`[GI$+X[
MD&P*)X>\=S3]`$ZO?`\%0T"2`)YL'7>0LHW9[3!VB8Y`DCA(!N#9DRAL?`R'
M^\\P]J3'PT,8/\\L;&[1"F;`&PM<&%3(84`-2XQX.PW##J*![S![*C4>?B2T
M^(*P-2FA=2K<BI78=N4L@@<_N-,[EMAIL PROTECTED]'!+(L!'$"BCHB1<CCM=R0M-9\>&#
M<<>UOMJ2WPCO7,H2G+-%C#%XQ/;?I&&(9_!`Y(7.W`,[EMAIL PROTECTED]</<%;
[EMAIL PROTECTED](B_"M&&%3(##=U5B`]^%`"F\GZ4?L02G/Z>5`-(IXAO.MESGBL^=/Z3
[EMAIL PROTECTED](S@,M<)VC7&/(O<.]"6M?+Q=`Y=%$)0Q9BP#$,O`U4W!`Q.B':$
M&A[[+ER2O/QY7D03!!@@V:JZ#6XN#.0L\!ESZ<8#Q=PBLR?N?*[QM/>@Z?JF
MX:;':+!T_)#TKL:][A6"_R4"FAS<\HO;9>29#`80UOWT#G<@NI->OX?9Q"3U
MJE)5J[_C\<3?\;".MSZ,]*A5F%U1;\X6'3'9H)K";3RW.(EF8OT/L7-MA,#H
M,`E(*3XP<:&MV5H%OJO5*D^,V"QAG$0NJ`2TSING$$]L(IL'V\NI+6V$^CW]
M=C0<CWC+P?-]8VNSWYUV-WV'@`(@`W"\?*LRO_[J\)UWPR)JS7L7^`\N:*0*
MUK\W`JM*K>CS/*#S+U^_'ZI22U&E1JV%%!KB6:)>WV[EU=.:^DVMO*J28T5J
M_YB'"7!$UV'$MVTBC!+RU>WW"N9_]6U"W([EMAIL PROTECTED]:#`<<1,@!^GU
[EMAIL PROTECTED]"5^%?%0=BO$""@GX]1D9W5Y=00#P$#^<1;;-
M5\'3[>-SPV4A90PR\_$Y?01E`R#F'`!S(1<]"P:;G:_4V<W2LY!83+-@(%H;
MY!_66U)6M$P7$(\%8^*8SGP=EF&UA,R6.]D:20[A(Y9)Y%$QQA*!J;R"Y9:G
M^HR"D)&6`K?`(7[5X(1-2C\)S94Q:[EMAIL PROTECTED])0.?G-H8&5<!#P*`*#9HN$!<E$(
M*+0X'CD>#$<?NVB"OQ!Q32"NH80/"WP-*,7:/B>20(_T8D-]EK^0G\[X_:4/
MS?LD<W_AH(*5\,Y9K;"[EMAIL PROTECTED]'AB,.P8N<0X:1&VBJX&(,JR%
M#PX^?J84E2\Q:M,(=[/;*<$>@[EMAIL PROTECTED]()7$$QG/2]&$G-X[0<86(9'
ML/[EMAIL PROTECTED]((T[QIH$/(048D<M.BREKPSGX
M!9+FGDT$TH2'^"!H2P5/2'G!X['5CL^(H/19^M(1RZC&H^UE4'Q#J6/<-I1V
MZE-Y?7&.1OX>#<V=>]%T[3C7:-P??(PIJ#*GH-9)`_QY-PY!43P`;[EMAIL PROTECTED],&H<
MNQ3'4X5D.3D^SY55)+D=K:]`ME.,$1>7/L_@>DU^VB:3T8KG9\KS2TIH$AG]
MNZXF>MY*.SJD:6=)K=(.(:"[EMAIL PROTECTED],&^2[1GR"+87/@XYV(*Q6'G$N"$^)!B
MW!N.:\Q<NL/:Q>WD4\P9U$>E!IPU6PEGVSP<GYM1H&>3+3I`=9;JKH<5!O/!
M,VU%>[EMAIL PROTECTED]/Q"E'[EMAIL PROTECTED](SI"C&RV9IP^ZPEP*WO`V9\X\F:1)
MAIBHQB%-5YB"\?S7>-Q[6-3PUYR6D]/005JS>>[EMAIL PROTECTED],9D*2X`W`;8IM?$LWV
M&9$Z<=_]R\[K%'G[EM_&&-K^,X?Y$L,>'?%&[EMAIL PROTECTED];L9>8'NV`4EZT1+5[
MR<=;*E'1!IA11#`A`6#S;FFXT,:7L*;Y=FE3"<L5\O[R1O\PT$:#JW(Y0QYN
M,?C/-4L*3#SE:%X/KCG-`NR#,I%,[EMAIL PROTECTED](RUB=R"%!2766!,^,GQ
M^<.U\7C#[U(347:3"LQA<+('!M##:G(MXY!\]AQH<M<[(_N:$0["8_B,[+8@
M8C,Q>M(RB!.\[XB3'+<K7YXMJC;<A&`+31P\ZO%%N+/9CVF5TNL6=+;S,A&M
[EMAIL PROTECTED]&WB%XPI]&[EMAIL PROTECTED](1295Y1+9U]AKK
[EMAIL PROTECTED];[0;[1E[&+P"Q):K'/QA!&KB'.FP[PD;9%.<G_VR&NX$3.0_UD_
MY9CC5Y37,!,?>9D9Q(8<<&1;,GPWJ\DSSVMX3<Z\EME$QK]=%/`(57B$"L5!
MX'9<'G8Y_!6R:[EMAIL PROTECTED])C0U["5LZ*;!B))%K.D''[EMAIL PROTECTED]:-5673PO-8
MP9GN!'_R608!+YV0TGER:M=Y<FICCMKPB,\W.17EF42P72Y%NGJ&2V03V\`-
MHTET"I9QQHDG`;[ENL?G_.H+#:1NN\8\)&[EMAIL PROTECTED]"Y.6ZB\_8(X
MB:?LR!-ZUCYYXJ3Z%8&VQ-C*,[EMAIL PROTECTED]'DZX(U)9Y=Q!<T[/[EMAIL PROTECTED]>BON
MHIS5`\:>H`S_PSK%JQ%6Y+AH'E1$TBYS/[EMAIL PROTECTED]&5DF>42G3XXH@"EGJEQ`^
MY4U.QS?"JGA)!_NM(FQP7:HJI79#DE*).%3R$`Z`K<Z&"NX)$F]36,%32\C6
M(DUA-/&"(+K2327BQ2#>J^Q4J4U!*."C<T#G#G;[EMAIL PROTECTED]
[EMAIL PROTECTED])**`=013*`+"\\K%[]6I,>/HESJ;_TEC+JAY%T;+LU9;:=BUFEK\'YYG
&Y'>T(P``
`
end
-------------------------------------------------------
This SF.net email is sponsored by: The Robotic Monkeys at ThinkGeek
For a limited time only, get FREE Ground shipping on all orders of $35
or more. Hurry up and shop folks, this offer expires April 30th!
http://www.thinkgeek.com/freeshipping/?cpg=12297
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel