Hi, this incorporates Greg's suggestions. I am still working at understanding the driverfs code. So that is not cleaned up.
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], 2002-10-11 21:51:28+02:00, [EMAIL PROTECTED] - proper configuration change handling diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Fri Oct 11 21:52:51 2002 +++ b/drivers/usb/core/hub.c Fri Oct 11 21:52:51 2002 @@ -1236,7 +1236,7 @@ return 1; } - ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue); + ret = usb_physical_set_conf(dev, dev->actconfig->bConfigurationValue); if (ret < 0) { err("failed to set dev %s active configuration (error=%d)", dev->devpath, ret); diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c Fri Oct 11 21:52:51 2002 +++ b/drivers/usb/core/message.c Fri Oct 11 21:52:51 2002 @@ -838,6 +838,54 @@ } /** + * usb_physical_set_conf - send the actual message changing configuration + * @dev: the device whose configuration is being updated + * @configuration: the configuration being chosen. + * Context: !in_interrupt () + * + * Caller must make sure that disconnect processing waits for this to complete + */ +static inline struct usb_config_descriptor *find_valid_config(struct usb_device *dev, int configuration) +{ + int i; + + for (i=0; i<dev->descriptor.bNumConfigurations; i++) { + if (dev->config[i].bConfigurationValue == configuration) { + return &dev->config[i]; + + } + } + + return NULL; +} + +int usb_physical_set_conf(struct usb_device *dev, int configuration) +{ + int r; + struct usb_config_descriptor *cp; + + r = -EINVAL; + cp = find_valid_config(dev, configuration); + if (!cp) + goto err; + + r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, configuration, 0, + NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); + if (r) + goto err; + + dev->actconfig = cp; + dev->toggle[0] = 0; + dev->toggle[1] = 0; + usb_set_maxpacket(dev); + +err: + return r; + +} + +/** * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated * @configuration: the configuration being chosen. @@ -871,7 +919,7 @@ { int i, ret; struct usb_config_descriptor *cp = NULL; - + for (i=0; i<dev->descriptor.bNumConfigurations; i++) { if (dev->config[i].bConfigurationValue == configuration) { cp = &dev->config[i]; @@ -883,17 +931,28 @@ return -EINVAL; } - if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, configuration, 0, - NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0) - return ret; + down(&dev->serialize); - dev->actconfig = cp; - dev->toggle[0] = 0; - dev->toggle[1] = 0; - usb_set_maxpacket(dev); + for (i = 0; i < USB_MAXCHILDREN; i++) { + struct usb_device **child = dev->children + i; + if (*child) { + ret = -EBUSY; + goto err; /* refuse if children were harmed */ + } + } + + usb_reap_interfaces(dev); /* get rid of all interfaces */ + + if ((ret = usb_physical_set_conf(dev, configuration))) + goto err; + + dev->desired_conf = configuration; /* for pm */ + + ret = usb_logical_register_dev(dev); /* reevaluate device */ - return 0; +err: + up(&dev->serialize); + return ret; } diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Fri Oct 11 21:52:51 2002 +++ b/drivers/usb/core/usb.c Fri Oct 11 21:52:51 2002 @@ -75,6 +75,7 @@ { struct usb_interface * intf = to_usb_interface(dev); struct usb_driver * driver = to_usb_driver(dev->driver); + struct usb_device * udev = interface_to_usbdev(intf); const struct usb_device_id *id; int error = -ENODEV; int m; @@ -94,7 +95,9 @@ if (id) { dbg ("%s - got id", __FUNCTION__); down (&driver->serialize); + down (&udev->serialize); error = driver->probe (intf, id); + up (&udev->serialize); up (&driver->serialize); } if (!error) @@ -110,10 +113,12 @@ { struct usb_interface *intf; struct usb_driver *driver; + struct usb_device *udev; int m; intf = list_entry(dev,struct usb_interface,dev); driver = to_usb_driver(dev->driver); + udev = interface_to_usbdev(intf); if (!driver) { err("%s does not have a valid driver to work with!", @@ -132,10 +137,10 @@ } /* if we sleep here on an umanaged driver - * the holder of the lock guards against + * the holder of the lock guards against * module unload */ down(&driver->serialize); - + down(&udev->serialize); if (intf->driver && intf->driver->disconnect) intf->driver->disconnect(intf); @@ -143,6 +148,7 @@ if (intf->driver) usb_driver_release_interface(driver, intf); + up(&udev->serialize); up(&driver->serialize); if (driver->owner) __MOD_DEC_USE_COUNT(driver->owner); @@ -317,7 +323,7 @@ * usb_driver_release_interface - unbind a driver from an interface * @driver: the driver to be unbound * @iface: the interface from which it will be unbound - * + * * This should be used by drivers to release their claimed interfaces. * It is normally called in their disconnect() methods, and only for * drivers that bound to more than one interface in their probe(). @@ -761,6 +767,26 @@ return -1; } +/** usb_reap_interfaces - disconnect all interfaces of a usb device + * @dev: pointer to the device whose interfaces shall be disconnected + * Context: !in_interrupt () + * + * Getting rid of interfaces associated with drivers. + * This is for physical disconnection and configuration changes + */ +void usb_reap_interfaces(struct usb_device *dev) +{ + int i; + + if (dev->actconfig) { + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { + struct usb_interface *interface = +&dev->actconfig->interface[i]; + + /* remove this interface */ + put_device(&interface->dev); + } + } +} /** * usb_disconnect - disconnect a device (usbcore-internal) * @pdev: pointer to device being disconnected @@ -792,14 +818,7 @@ usb_disconnect(child); } - if (dev->actconfig) { - for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { - struct usb_interface *interface = &dev->actconfig->interface[i]; - - /* remove this interface */ - put_device(&interface->dev); - } - } + usb_reap_interfaces(dev); /* Free the device number and remove the /proc/bus/usb entry */ if (dev->devnum > 0) { @@ -923,6 +942,66 @@ } /* + * Logical reevaluation of a device - for new devices or configuration changes + */ +int usb_logical_register_dev(struct usb_device *dev) +{ + int err; + int i; + + /* + * Set the driver for the usb device to point to the "generic" driver. + * This prevents the main usb device from being sent to the usb bus + * probe function. Yes, it's a hack, but a nice one :) + */ + dev->dev.driver = &usb_generic_driver; + dev->dev.bus = &usb_bus_type; + if (dev->dev.bus_id[0] == 0) + sprintf (&dev->dev.bus_id[0], "%d-%s", + dev->bus->busnum, dev->devpath); + err = device_register (&dev->dev); + if (err) + return err; + + /* add the USB device specific driverfs files */ + usb_create_driverfs_dev_files (dev); + + /* Register all of the interfaces for this device with the driver core. + * Remember, interfaces get bound to drivers, not devices. */ + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { + struct usb_interface *interface = &dev->actconfig->interface[i]; + struct usb_interface_descriptor *desc = interface->altsetting; + + interface->dev.parent = &dev->dev; + interface->dev.driver = NULL; + interface->dev.bus = &usb_bus_type; + sprintf (&interface->dev.bus_id[0], "%d-%s:%d", + dev->bus->busnum, dev->devpath, + interface->altsetting->bInterfaceNumber); + if (!desc->iInterface + || usb_string (dev, desc->iInterface, + interface->dev.name, + sizeof interface->dev.name) <= 0) { + /* typically devices won't bother with interface + * descriptions; this is the normal case. an + * interface's driver might describe it better. + * (also: iInterface is per-altsetting ...) + */ + sprintf (&interface->dev.name[0], + "usb-%s-%s interface %d", + dev->bus->bus_name, dev->devpath, + interface->altsetting->bInterfaceNumber); + } + dbg ("%s - registering %s", __FUNCTION__, interface->dev.bus_id); + device_register (&interface->dev); + usb_create_driverfs_intf_files (interface); + } + + return 0; +} + + +/* * By the time we get here, the device has gotten a new device ID * and is in the default state. We need to identify the thing and * get the ball rolling.. @@ -1008,7 +1087,7 @@ } /* we set the default configuration here */ - err = usb_set_configuration(dev, dev->config[0].bConfigurationValue); + err = usb_physical_set_conf(dev, dev->config[0].bConfigurationValue); if (err) { err("failed to set device %d default configuration (error=%d)", dev->devnum, err); @@ -1026,55 +1105,14 @@ usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); #endif - /* - * Set the driver for the usb device to point to the "generic" driver. - * This prevents the main usb device from being sent to the usb bus - * probe function. Yes, it's a hack, but a nice one :) - */ + usb_generic_driver.bus = &usb_bus_type; dev->dev.parent = parent; - dev->dev.driver = &usb_generic_driver; - dev->dev.bus = &usb_bus_type; - if (dev->dev.bus_id[0] == 0) - sprintf (&dev->dev.bus_id[0], "%d-%s", - dev->bus->busnum, dev->devpath); - err = device_register (&dev->dev); + + err = usb_logical_register_dev(dev); + if (err) return err; - - /* add the USB device specific driverfs files */ - usb_create_driverfs_dev_files (dev); - - /* Register all of the interfaces for this device with the driver core. - * Remember, interfaces get bound to drivers, not devices. */ - for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { - struct usb_interface *interface = &dev->actconfig->interface[i]; - struct usb_interface_descriptor *desc = interface->altsetting; - - interface->dev.parent = &dev->dev; - interface->dev.driver = NULL; - interface->dev.bus = &usb_bus_type; - sprintf (&interface->dev.bus_id[0], "%d-%s:%d", - dev->bus->busnum, dev->devpath, - interface->altsetting->bInterfaceNumber); - if (!desc->iInterface - || usb_string (dev, desc->iInterface, - interface->dev.name, - sizeof interface->dev.name) <= 0) { - /* typically devices won't bother with interface - * descriptions; this is the normal case. an - * interface's driver might describe it better. - * (also: iInterface is per-altsetting ...) - */ - sprintf (&interface->dev.name[0], - "usb-%s-%s interface %d", - dev->bus->bus_name, dev->devpath, - interface->altsetting->bInterfaceNumber); - } - dbg ("%s - registering %s", __FUNCTION__, interface->dev.bus_id); - device_register (&interface->dev); - usb_create_driverfs_intf_files (interface); - } /* add a /proc/bus/usb entry */ usbfs_add_device(dev); diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Fri Oct 11 21:52:51 2002 +++ b/include/linux/usb.h Fri Oct 11 21:52:51 2002 @@ -375,6 +375,7 @@ int have_langid; /* whether string_langid is valid yet */ int string_langid; /* language ID for strings */ + int desired_conf; /* configuration to restore on resume */ void *hcpriv; /* Host Controller private data */ @@ -1032,6 +1033,9 @@ struct scatterlist *sg, int n_hw_ents); void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, struct scatterlist *sg, int n_hw_ents); +void usb_reap_interfaces(struct usb_device *dev); +int usb_physical_set_conf(struct usb_device *dev, int configuration); +int usb_logical_register_dev(struct usb_device *dev); /*-------------------------------------------------------------------* * SYNCHRONOUS CALL SUPPORT * =================================================================== This BitKeeper patch contains the following changesets: 1.890 ## Wrapped with gzip_uu ## begin 664 bkpatch1735 M'XL(`!,LIST``ZU9^U/;QA;^V?HKMG22`L&VWGX0,B1`$T\I20ET;F_3\<C2 MVM8@2QH](+G7_._]SJXDRUB$0DD\EKQ[]NS9<[[S6GYDERE/AJTH\*]YHOS( M/D1IAI\\C$+>F4<+'OAA_K43)3-,GD<1)KLTW)4KNI.K=I9PGG;Y5]U20//) MR=PYPU0Z;&D=HQK)OL5\V#H_>7]Y^O9<40X.V-'<"6?\,\_8P8$RN3KT<AYT MKI+(F=-VRVIZJ:NJIFFZI1J6K5E+O6\8YE*SU8F'5T_O#:83>Z`DGI>'@1,? M1JD7;'+0-57MJSW=M+2ET3-[`^68:9W^0&6JWM74KJ8Q71M:VE#OOU+UH:HR M><+#)EVP5R9KJ\H[]N_%/E)<UF9Q$L4\86X43OU9GCB9'X7,%:P8OCWL/%-^ M8::AFI;R::4ZI?W(?XJB.JKRALT2/CN44KO18NDE=-:TFZ>3KALEO+O@:>K, M>,<5NE-MU=`LT]3LI:;:YF`YM2W3Z)L]V^MK?=68?$]9#S'72$T#J&FP-,'+ M@G2;:O5#-\@]WA5<B5-GOE*PJ5JFNH1@9F_IZ;KA]3W+FMJF86O?%>P>IG6) M#%W5[$:)ZJ>BI6Y=G@$TI1NF92Y=6^?<ZNM:SYTXAFH]3E,5X[I,>E\?&`_* M-,\;9#(T4S>6KN;84ZMGF*8WL:S>(V6J&-=E4C7+-H5;-],W^_@3Y54>0F]= M1/B\JMMP/8C8MX77V\:ZTZM#8_!/G%YC;>T9G?Z.MP?<"?,87BY4^9&UDQOQ M@=-^ND>K3W#_8TTW!DQ31L6SE5``9N`[CN??4M]U@G'*LS$)M^WQZSV&K_8; MQ\VDN.TWDZ.ZW+\[0<YW]IM-+^#[L.D?X3X/FK[N,97I==52I>DUA(0GV7Y@ ML;;5>_Z0'T3N%8([FT;-X3\5Q'XX39PT2W(WRQ-^+W$]5\@H\1",A+J>`*-1 MKT?@D2()]``FOLO9+D-$O0:B('/&DZGC\G$6C4&!X6V,30&6T<"FU2TON@G9 M]LM<0`R%B.\$_O^X(!#L6WG</`TEW[,]$0L"L4,ARW=$.=8,2[B#>+0@?S:' M'J/`@W&BJ?A%-F*SW$F\E#DSQP_3C-;UY3IZB),T2VH*OGG<-'N,]$),Y(/M M0JV(3;JJ='=WQ:D2[L3C2OH42/#\%)8/.8[M!`&KS4%8AQ8QJ0JP8^P0[T,6 M1X*,99$X3J&JFWF4\CJ#=$X<)[RV!_<$&WA\QK]F0_:#'TIQDCS.V/8.R4P$ M[WF6$8H3WR,Y:DR=-(U<WP$G=N-G\Q*!';'L8NZG#!_"<QE]:KL3L`'H>_R" M[7:5ZP@;-BAJNP$9>.XH_U=:H&+^OO(%;U.VO1[==A@(6B3.M@_<J/O,9Z\W M(^!9OAA5>X'FU2NYL`[(2ABVNWH]8"_O,JLF__3_$E*U6MU=EO!%=,UA+E+0 MBE.7IN,\*PZU_;*::[^A\^UC_E;!YU8Y[B%D]9517Q6NTJ0DN6(TT"UFJV20 MTV@F3("*_AIQ7>I;X*I08EN8*N0WQ0!0=U_8(F%)U;1Q(/E"@)F?8GL2_R$3 M`6/[E;%:"I0BO)/Z!0%B@2,A#OU<X9Y0+@!?PGUKQD/XG+M5K.D(/@)Z<<*O M>9BE@FX!QZ[SF2;1`MY`L$[YBAU13/)4,$$,A[M,\U!@M</8'SS=8W[V$W"/ M6.Q>[8$4CLI"8HBLPH8[M!!F%##`5Z<X")!!FBAD'<O1_1H=]BR)\#JF?FJ_ M!N&"9.Q[?ZI_(>4R%3NUTCBA.(<@NDFTQ[9>>.T7Z=8>@4J"')/B*\P71>+' M5^QD<T(6+`()I'8J4]98[Q3R@([V1F&1)Z&TXQ>R'W,\3ZCP\O.[4LEIS%U_ MZKN%;::(!7X`6)&*Z*@N,)OQ<3E+2!E+B@*]DO-Y*0U%L")JUX*01`D,7H8^ MBD0U%%$JE+`XYPN^F/!DK[Y\!LQ-HAR1"!@H`M@>"Z.L](*.D/?)8>-?1XUF M%E!6ZB9^G$&N77JO9T)P"[)4AFT9=M9#22=V$D)]N;=(JQM$%7C/+D]/&^:; M05N#Y2;].CB'+[Q_A$])TW@Z+*BT#@O`N"),$E)_(*U`F=4\<6DMET*/4"GY M?ED$KQ.*_3:.&SJ+<B9%AJ]GPA7!#GM-WBD3!K`+I5!P#+Y5,?4F"G\BQ`&A MB<2J7Q<0,"TMBZ@#(&5%&B5$AU&R0`1WG90C'CEAL:!B@-!4&&WAS^99P0E1 MS,>.4)B(CV+)MA.DT9"MSDQ;H&1MKU3+.IW.CB07F>E>N]*YR:I"-UO0+DR+ M3RVUE79NK=EY+#2Z:>G68RQ]2Y7F!);<>D$55!FY2'Z*?FP\_OGR[.AB]/%L M/-Z[:S&)2,%G,_(U9-^FH$4Z*:-6M82H;RFQ%7%2W4?2_H+_2'3'U%F+ZE(^ MB]#[4),F@P/TW&GNT<!6'S"+V!H&V'ZA$<-F-HV8&C-(G-56C5F[.">M-$UF MR)Z_X2*EN>M[ZC7.W;;O_IL;\++!IK=4!P/+DCV?JCZMYWOF2[ZR3J"R(8LH M%J;HT^0-TYT^K>%\3VG2#-FE43$$/_<3[@G([(NXLUZV(;,E/$6JH#J%7O.% MJ#<)*[#SHROM_:KXVT1L\Q+A>NM2U;@\IH2\YS:BNG8D;#[S!>@C^=6OI2Q3 MUR5.>T^#J3U@;>TY@0J!$VHPR]L$JJB:B_Q?F+RR?>B:H3K]4U#<-U5L0_U) M(YP@,.IS65FB0LJ1_8KMI)AT@#7IB9-LC#>ZX?53(M_)^C^//:?HA0_72"2+ M]55RB4O\0M'F/M0]'R'Y4S[.TPQ-R!6*8KKCR>9.5N_V$33@;BGQOG'\K%;4 MPG4!N3C@&1==5YI!$!?>!-N!V<I'I)QK9>'4#[TQ>CW?*V8?X9SKS;2L?@^H M]GU=Y.MRFPY5OFL9J5[]5BU,D;[\QO1%+<WZ]K*`*K+GRW4.LJ*]7<^PLD:E M)/L<H:D\/35IW]>Q&XL&EM)J^V1T]OM;JI3=&#\WM2\VNQL#9:WJQE1JS9`Z MJIZJS-18D"51,%ZD!0=1OX:>FR5![,=<#JH[LG9"^S4^/_EM_/GD8GST\>SG MT?O+\[=4_H#DSN8T(M:0[L3TA_\"L<3AZ.+\5+"X&/UZ\O'RHI0SV9!RO7>! MR$(A8C2+9K.`BXZ5"J"U0:T<%(>!@1;.UQ@]-<^JU@\[#"OSBLUN10&%"JK? M,ZF`D@\4.OV^S4S\[@]6UW6;]W']@2:H!EAE;W9T=.Y?W_[GZ,/H]/C\Y*RY MA2MQL^O._<"3'3.@23_04;%7XCY#J$I2K(`L`/+N\O,?1+#2(1/W0=.<;NL0 MB$M&-SRA"]]DP3U9?@NX?_G.50\QHEZVN*6[<W\('L6=V/:#?Q-81^A.L\GK M)0>[X[U"%G'MMR@V7NUY?]TI-5'<356A&^MA.%N8&P^C@`5=N6Y8N`(+S_97 :?ZYVY]R]0L5SH#ONU%&-@?(WX$9?E1D?```` ` end ------------------------------------------------------- This sf.net email is sponsored by:ThinkGeek Welcome to geek heaven. http://thinkgeek.com/sf _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel