On Mon, May 31, 2004 at 02:15:23PM +0200, Oliver Neukum wrote: > Hi, > > I am sorry. I should have sent you this long ago. > > Sorry > Oliver > > Signed-off-by: Oliver Neukum <[EMAIL PROTECTED]>
Signed-off-by: Vojtech Pavlik <[EMAIL PROTECTED]> Greg, another one for you, and you need to apply this one first. Oliver - thanks, I suppose this will fix problems with some of the devices that have slightly unusual descriptor sets. > > 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-05-30 10:50:37+02:00, [EMAIL PROTECTED] > - fix probing to use cdc union descriptor > > > cdc-acm.c | 274 ++++++++++++++++++++++---------------------------------------- > cdc-acm.h | 114 +++++++++++++++++++++++++ > 2 files changed, 214 insertions(+), 174 deletions(-) > > diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c Sun May 30 10:56:45 2004 +++ b/drivers/usb/class/cdc-acm.c Sun May 30 10:56:45 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]; @@ -567,77 +477,102 @@ * USB probe and disconnect routines. */ -#define CHECK_XFERTYPE(descr, xfer_type) (((descr)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == xfer_type) - static int acm_probe (struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device *dev; + 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; + struct usb_endpoint_descriptor *epread; + struct usb_endpoint_descriptor *epwrite; + struct usb_device *usb_dev = interface_to_usbdev(intf); struct acm *acm; - struct usb_host_config *cfacm; - struct usb_interface *data = NULL; - struct usb_host_interface *ifcom, *ifdata = NULL; - struct usb_endpoint_descriptor *epctrl = NULL; - struct usb_endpoint_descriptor *epread = NULL; - struct usb_endpoint_descriptor *epwrite = NULL; - int readsize, ctrlsize, minor, j; - unsigned char *buf; - - dev = interface_to_usbdev (intf); - - cfacm = dev->actconfig; - - /* We know we're probe()d with the control interface. */ - ifcom = intf->cur_altsetting; - - /* 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 find - * it - */ - for (j = 0; j < cfacm->desc.bNumInterfaces; j++) { - ifdata = cfacm->interface[j]->cur_altsetting; - data = cfacm->interface[j]; - - if (ifdata->desc.bInterfaceClass == USB_CLASS_CDC_DATA - && ifdata->desc.bNumEndpoints == 2) { - - epctrl = &ifcom->endpoint[0].desc; - epread = &ifdata->endpoint[0].desc; - epwrite = &ifdata->endpoint[1].desc; - - if ((epctrl->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN - || !CHECK_XFERTYPE(epctrl, USB_ENDPOINT_XFER_INT) - || !CHECK_XFERTYPE(epread, USB_ENDPOINT_XFER_BULK) - || !CHECK_XFERTYPE(epwrite, USB_ENDPOINT_XFER_BULK) - || ((epread->bEndpointAddress & USB_DIR_IN) - ^ (epwrite->bEndpointAddress & USB_DIR_IN)) != USB_DIR_IN) { - /* not suitable */ - goto next_interface; - } - - if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) { - /* descriptors are swapped */ - epread = &ifdata->endpoint[1].desc; - epwrite = &ifdata->endpoint[0].desc; - } - dev_dbg(&intf->dev, "found data interface at %d\n", j); - break; - } else { -next_interface: - ifdata = NULL; - data = NULL; + int minor; + int ctrlsize,readsize; + char *buf; + + if (!buffer) { + err("Wierd descriptor references"); + return -EINVAL; + } + + while (buflen > 0) { + if (buffer [1] != USB_DT_CS_INTERFACE) { + err("skipping garbage"); + goto next_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]; + } + + if (!union_header) { + dev_dbg(&intf->dev,"No union descriptor, giving up\n"); + return -ENODEV; } - /* there's been a problem */ - if (!ifdata) { - dev_dbg(&intf->dev, "data interface not found\n"); + 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) { + dev_dbg(&intf->dev,"no interfaces\n"); return -ENODEV; + } + if (usb_interface_claimed(data_interface)) { /* valid in this context */ + dev_dbg(&intf->dev,"The data interface isn't available\n"); + return -EBUSY; } + /*workaround for switched interfaces */ + if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { + if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) { + struct usb_interface *t; + dev_dbg(&intf->dev,"Your device has switched interfaces.\n"); + + t = control_interface; + control_interface = data_interface; + data_interface = t; + } else { + return -EINVAL; + } + } + if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) + return -EINVAL; + + epctrl = &control_interface->cur_altsetting->endpoint[0].desc; + epread = &data_interface->cur_altsetting->endpoint[0].desc; + epwrite = &data_interface->cur_altsetting->endpoint[1].desc; + + + /* workaround for switched endpoints */ + if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) { + /* descriptors are swapped */ + struct usb_endpoint_descriptor *t; + dev_dbg(&intf->dev,"The data interface has switched endpoints\n"); + + t = epread; + epread = epwrite; + epwrite = t; + } + 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; @@ -647,21 +582,21 @@ dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n"); return -ENOMEM; } - memset(acm, 0, sizeof(struct acm)); ctrlsize = epctrl->wMaxPacketSize; readsize = epread->wMaxPacketSize; acm->writesize = epwrite->wMaxPacketSize; - acm->control = intf; - acm->data = data; + acm->control = control_interface; + acm->data = data_interface; acm->minor = minor; - acm->dev = dev; + 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))) { dev_dbg(&intf->dev, "out of memory (buf kmalloc)\n"); kfree(acm); @@ -693,29 +628,17 @@ return -ENOMEM; } - usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress), - buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); + usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), + buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); - usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), - buf += ctrlsize, readsize, acm_read_bulk, acm); + 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_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), - buf += readsize, acm->writesize, acm_write_bulk, 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; - if ( (j = usb_driver_claim_interface(&acm_driver, data, acm)) != 0) { - err("claim failed"); - usb_free_urb(acm->ctrlurb); - usb_free_urb(acm->readurb); - usb_free_urb(acm->writeurb); - kfree(acm); - kfree(buf); - return j; - } - - tty_register_device(acm_tty_driver, minor, &intf->dev); - dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); acm_set_control(acm, acm->ctrlout); @@ -724,11 +647,14 @@ acm->line.databits = 8; acm_set_line(acm, &acm->line); + 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; } -#undef CHECK_XFERTYPE 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 Sun May 30 10:56:45 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.1758 ## Wrapped with gzip_uu ## M'XL( ,VAN4 \59>W/:[EMAIL PROTECTED] (,/J="@[EMAIL PROTECTED]<'93FY1* M2 /H+"16&MGQ'?[NUSTCB8?D1U*;NL2Q9C0]W;[EMAIL PROTECTED],HXX4^MX-C>07 MY)]AS#K2TG:FE"UJ 4VNDV4MC.:P9(8A+-47X9+6!7U]$E$:UYFMR;#^T6;. [EMAIL PROTECTED]".I-3U_P^Y6M"[EMAIL PROTECTED]&]A!W,ZIHR<G<DLC&YLWXW?V&SA MAT&-1780+RFS:TZX7.>D:TU1-/C;4%NZTFBNU:9BM-:.ZJJJ;:C4533CI&G( M\XC.WUQ'H;TH;C>4AG:BJ<J)UEH;BF&TY3Y1:VJK<4(4HZXTZKI"5*734#IZ [EMAIL PROTECTED]>=\4]0'^54CQXK\EOR]\'NR0X[)S/M&5E$X]8(Y\"=)3(GC.B0) MO# @+HV=R%N!7/D#:1AMY43^N-&H?/R=?V19L17Y]<,G7;L1KL3U))[6'=^. MXSJ .;:=96V1:E57E);65K6UHBLM8]W2FHHS;=HG;:=E:X;S=_#6UXK::#4 MZ.,*WV:(;)PMQ1N*VEHWFJUV<SUU],9,56>:H<]TVIK^$$1G _'$:&C:NM%H [EMAIL PROTECTED])]V'B.49X020_X$_^2?:!T>!,HF I1V1VMW5.WI"%!^ [EMAIL PROTECTED]'/E"ZHA%7$2E/./7'%/>!X$DA+!XC,DE!$W\0Y1LDB!^(H9]N(/5' M#*2JQL])4N^("DKF 7E)CJ-;[EMAIL PROTECTED]>%SCWZ_6(21DU9#K1S+!'S(,'#^!!$AF M843R,$P7+VPO\.\(LZ\IF47A$O+F-*#L5<[EMAIL PROTECTED] M:U9)#'Y&[,A9>(PZ+(E C&,'KQA9V#>4Q"O;@>7 )4L[ND9&'KNKI8Q>>+/ MI;.4E?P"QEY TZDD28K\@@:N-\ME7MC_AA-P;EX HR!93D%M.;^40;=W84TF [EMAIL PROTECTED]:;!:7AJ-+<RQ)NI8S-^E?"[EMAIL PROTECTED] MO?/N>$S68G70&WZTAJ/)P'S7[0T.]Z"[EMAIL PROTECTED]"JCD8?[P< MC0>XJA96QX.)]6[0G5R9G$ K$+S?)="+TL\'77.;Q"B!B&+.AR-<UXH0WV^M MED/L78XFYN4Y$A0AC@>COO76''0_X+J>*WUH_E9J/GAOC0:3WR_-#R4ZPU4$ M8XTGW4D*..-XF;[EMAIL PROTECTED]>+#GE()O8EY;O4GIE14.E\R)V-)J#O'&A08 M<U_$$:%1%)9[HA#4ZS\DJ#\VI:)=^=+;]/1&";PA7SDI$_;.[()_OX=U52FN M0FP-)[EMAIL PROTECTED]>C6#5V.CT'$GB%:4N/[!C1[;#("_0P E=:+>R8\<L M2AQ&(+U87"G_E27+2G1-[#WELQ,2LW U]5B<S452R&:NS6RQ>D\LRV8L\J8) MHY9%*A5()M?4/3P\W;()X AL/[EMAIL PROTECTED]"# +%3$A'#2&>0XRZ4W'N2F(WB>0K*1 MZD<$DAW8-X+=JS# @R$AR0CK.]L]E#S#[':4NL2I8)(YR!;[EMAIL PROTECTED]');O M8>S.2H=','X8+"SNR(JF@(U%/@RJY"BBMBM&MZ!O"L-39 //>'M7;CS\E<GB M+X2M206M4^56K*:V.]QF<!M&U];[EMAIL PROTECTED] 1B!11TQXL1Y^MZL>.M^/#6 MON9:7^V<WXZO?<HRGM-%RC'B[;Y#XQCWX(8DB+UY %X*>B1X<B_(3N"5!&\% MHK)*(/ZJQ!Q6R10T=%TE(?A1!)P.RUF&"<MXAB6I!IA.D-]D7+*?*S[V_I/K M=6G#&="I&<'77"=HUY3S-/&O05ON*L3=!79PPW$S3EB&[EMAIL PROTECTED]@Q>C':&& MI[X;KFA0W,^+:,8 V2[JNZ2.PL;D44A8S[=>*"8NV1ZQYW/M^]*-SI^Z-A^ MOHU&2R^,2>_\LM<]1_)[$=#DX(K?U=XE@<-@ &'=SZ]M!Z([Z?5[F$T<TJAI M-;WV!V[/_!TW6WC1PTA/3J3I.0WF;'$J)AM6$[A:[EMAIL PROTECTED] !UF M :FD&\8^M#4[;P%WK5;CB1&;)8R3Q >[EMAIL PROTECTED]/+7EC5"_9UV- MAI<CWG+P?-_<6>QW)]U-WR&H@,@&'H]?IYRG/R'\X)50=J"S#M[PWR&TU>Q/ M_+;P]1GW0575=+6MM]<&3 W>ON]]8C :'>TY_3LL'P/(__]G!GZQ?7:K[_Q( MJ]_4"#0.GNCPR4%^;3@ '^BW%-+6Y'X#GOS1@ O($!_M39'8!,V1&"[EMAIL PROTECTED]; MGI'1U?DY^#>/X*-I,IOQM^#(L^/7ML]BRACHX/@U_09J!4),*4#F0ZIYD P6 M3Y\HHYM7#U)BK7R(+$N7UL84Y(BN,'4_BQ#+Y+,(>3([EMAIL PROTECTED]"" MU_"[EMAIL PROTECTED] =[M$A#1Q.VB:H+_8F4+,8(&:M"%2'QJK%E#)ZGO!FI_"(L<[EMAIL PROTECTED] M3X+*53GXW:.1N^6))*) +T:C0] [EMAIL PROTECTED]/AJ-/733Q/3*[7>[EMAIL PROTECTED] MP==$$2Q11FK\/]6OY)<S?N7I0[\_WKKR<%(A/K[V5BL,CKD=3>TY%3*E>0C! M$H 3<#6>PK$AJ.$J 9*E^-;#3YZY'.UKRM"QX_TTV"'[EMAIL PROTECTED], MDH"Z[<,IDQ3710BYF4'($ZR3^^$*#4V&&[)YBKF(&M_=\]][P5(IB:=#<1ZQ MBW<7? @)W$Y\UI%S:,,[EMAIL PROTECTED]@FF&8;/Q7LZ1X.;44L=G1,CY4_EZ*EZC M$G_=?7V?^TM10^"4ECN=5UZ*H(5I]6 4EJAH[MV(]NQ+L.=)H\O^X!/X=%/7 M";JTWB &>.M^1(.B>"C/H,? B/!FE316JF0;U_'K0OU%>;MQ_QW,]JHV\N*Z M* )<K\DONV(>UE$0;I5UH1(X>1.2+*@;1BVB"SD[Z<N"K.\MJ5O9$P-RT+6A M7GG8GHDN#@&"S86'EV&80+>X=W7P8OS\8M_8GF]/?5JPU=NK\6>.M$UT#?L7 M;,WMB <3-J B&D6/N-6S\)/L8CY^[221M9WDT5MJTUS3/2QPF#,>Z%8V*:9@ MB6?R/GN"]P,5A*616%3HYS")LK89F^D2;=2$2C%S20R\L*QP2:7.7RA<4M&G M.;1[0OV8BA,4TC5FH/OOL<<H60[2(A:3?Q#ML*0(P&E$E00(+Y]AC:PJ0GJI MI;E1%$_<_Q2LTLV\H'[7;C7;_07AIY?,,D^F^>DS1ZX(L) ;,LUT71?NTC%Y M*0K<T [EMAIL PROTECTED]/4^*<-&"LA+?VJL5R.%A^E3KP W\S%C>\<#\%%E( MR\+_\J9E8X%->[*E6,;K@(1B#[9B&P_ LXY(8 ;[EMAIL PROTECTED]@$<3FL=AL]&" MAP2])[EMAIL PROTECTED]"6>SXGX<<H^CMP:V,/*AXI*6^4TLR- )I&"J M)+>Y9"28>3Z7 M9271M"[EMAIL PROTECTED])\W-ID?!I$#=8JMO!7=5 3AW$5['U8QQK!65C<[EMAIL PROTECTED]/+B_[B MLRT&/ .!PK"':[;;B+&E*#L8\>*^ 9E_>=D'B63[*,N],D6),+&R;X!FO:& MC#,NG$\18$O1!4#C$8#9!Z$]A''@EB'DU$]"W &6BM@ Y=-]I"VB(E2MB;T# M%\CO2J)@;MRH\A(YB+7JGHMEW" =X&<SN'IZV$:DG3F>UL+WV6;>;E?))@CY AUGY+5\$%\_^*A^!SKN-D>:8WV]2E)XK\/^:P A !( -- Vojtech Pavlik SuSE Labs, SuSE CR ------------------------------------------------------- This SF.Net email is sponsored by: Oracle 10g Get certified on the hottest thing ever to hit the market... Oracle 10g. Take an Oracle 10g class now, and we'll give you the exam FREE. http://ads.osdn.com/?ad_id=3149&alloc_id=8166&op=click _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel