UsbHubDriver.Mod 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566
  1. MODULE UsbHubDriver; (** AUTHOR "staubesv"; PURPOSE "USB 2.0 Hub Driver"; *)
  2. (**
  3. * Bluebottle USB 2.0 Hub Driver
  4. *
  5. * The hub driver is actually part of the USB Bus Driver and has direct access to the functionality offered by Usb.Mod.
  6. *
  7. * Usage:
  8. *
  9. * UsbHubDriver.Install ~ will load this device driver
  10. * SystemTools.Free UsbHubDriver ~ unloads it
  11. *
  12. * Overview:
  13. *
  14. * HubDriverInterface(Usbdi.Driver) Abstract class defining the interface to USB hub devices and USB root hubs
  15. * HubDriver(HubDriverInterface) Actual hub driver for both USB hub devices and USB root hubs,
  16. * based on HubDriverInterface
  17. * UsbHubDriver(HubDriver) Implements HubDriverInterface for USB hub devices
  18. * UsbRootHubDriver(HubDriver) Implements HubDriverInterface for USB root hubs
  19. *
  20. * References:
  21. *
  22. * Universal Serial Bus Specification, Revision 2.0 (available at www.usb.org)
  23. *
  24. * History:
  25. *
  26. * 24.11.2005 First release (staubesv)
  27. * 12.12.2005 Force check port status for USB hub devices to enumerate attached devices, use exception handling (staubesv)
  28. * 29.06.2006 Show overcurrent conditions on kernel log (staubesv)
  29. * 30.06.2006 Made HubDriver.Wait procedure EXCLUSIVE to protect timer from concurrent use (staubesv)
  30. * 03.07.2006 Bugfix: Correct address and port of transaction translator for low-/fullspeed devices connected to high-speed busses (staubesv)
  31. * 04.07.2006 UsbHubDriver.GetPortStatus: First ackknowledge change bits then evaluate port status (staubesv)
  32. * 02.08.2006 Bugfix in HubDriver.HandlePortStatusChange, adaptions to Usbdi (staubesv)
  33. *
  34. * TODOs:
  35. * - power management/saving
  36. * - overcurrent handling
  37. * - correct TT support
  38. * - device driver connect procedure blocks HubDriver.HandlePortStatus change -> shouldn't do that,
  39. * hubdriver should call connect itself, not as sideeffect of installing a driver via driver manager
  40. *)
  41. IMPORT SYSTEM, KernelLog, Usb, UsbHcdi, Usbdi, UsbBuffers, Kernel, Modules, Debug := UsbDebug;
  42. CONST
  43. (* Name and description of the integrated USB (root) hub driver *)
  44. Name = "UsbHub";
  45. Description = "USB Hub Driver";
  46. AllowSuspend = FALSE;
  47. (* Interval in milliseconds the root hubs are polled when interrupt notification is not supported. *)
  48. PollingInterval = 200;
  49. (* Hub class port status bits *)
  50. PsCurrentConnectStatus = {0};
  51. PsPortEnabled = {1};
  52. PsSuspend = {2};
  53. PsOverCurrent = {3};
  54. PsReset = {4};
  55. PsPortPower = {8};
  56. PsLowSpeed = {9}; (* IF status * {9, 10} = {} THEN Fullspeed *)
  57. PsHighSpeed = {10};
  58. PsPortTestMode = {11};
  59. PsPortIndicators = {12};
  60. PsConnectStatusChange = {16};
  61. PsPortEnabledChange = {17};
  62. PsSuspendChange = {18};
  63. PsOvercurrentChange = {19};
  64. PsResetChange = {20};
  65. PsChangeMask = {16..20};
  66. (* Hub class hub status bit *)
  67. HsLocalPowerLost = {0};
  68. HsOvercurrent = {1};
  69. HsLocalPowerSourceChange = {16};
  70. HsOvercurrentChange = {17};
  71. (* Hub Class Request Codes (USB2.0, p. 421) *)
  72. GetStatus = 0;
  73. ClearFeature = 1;
  74. SetFeature = 3;
  75. GetDescriptor = 6;
  76. SetDescriptor = 7;
  77. ClearTtBuffer = 8;
  78. ResetTt = 9;
  79. GetTtState = 10;
  80. StopTt = 11;
  81. (* Hub Class Feature Selectors (USB2.0, p 421- 422) *)
  82. HubLocalPowerChange = 0;
  83. HubOverCurrentChange = 1;
  84. PortConnection = 0;
  85. PortEnable = 1;
  86. PortSuspend = 2;
  87. PortOverCurrent = 3;
  88. PortReset = 4;
  89. PortPower = 8;
  90. PortLowSpeed = 9;
  91. PortConnectionChange = 16;
  92. PortEnableChange = 17;
  93. PortSuspendChange = 18;
  94. PortOverCurrentChange = 19;
  95. PortResetChange = 20;
  96. PortTest = 21;
  97. PortIndicator =22;
  98. (* Descriptor types *)
  99. DescriptorHub = 29H;
  100. DescriptorDevice = 1;
  101. (* UsbHubDriver.powerSwitching & UsbHubDriver.ocProtection values *)
  102. NotAvailable = UsbHcdi.NotAvailable; (* MUST be 0 *)
  103. Global = UsbHcdi.Global; (* MUST be 1 *)
  104. PerPort = UsbHcdi.PerPort; (* MUST be 2 *)
  105. (* Format of Setup Data *)
  106. ToDevice = Usbdi.ToDevice;
  107. ToHost = Usbdi.ToHost;
  108. Class = Usbdi.Class;
  109. Device = Usbdi.Device;
  110. Other = Usbdi.Other;
  111. (* HubDriver.EnablePortPower parameter *)
  112. AllPorts = -1;
  113. (* Device attachement/removal *)
  114. DeviceAttached = 0;
  115. DeviceRemoved = 1;
  116. (* Number of times the status pipe of USB hub devices is tried to be restarted when errors occur *)
  117. StatusPipeMaxRetries = 5;
  118. TYPE
  119. (* Interface to be implemented for both USB hub devices and USB root hubs *)
  120. HubInterface = OBJECT(Usbdi.Driver)
  121. VAR
  122. (** Note: Port numbers: 0..nbrOfPorts-1 *)
  123. (*
  124. * This hub class specific request returns the hub descriptor.
  125. * @param type: Descriptor type
  126. * @param index: Descriptor index
  127. * @param length: Number of bytes to load
  128. * @param buffer: Buffer where to put the descriptor in (at offset 0)
  129. * @return TRUE, if request succeeded, FALSE otherwise
  130. *)
  131. PROCEDURE GetHubDescriptor(type, index, length : LONGINT; VAR buffer : Usbdi.Buffer) : BOOLEAN;
  132. BEGIN HALT(301); RETURN FALSE; END GetHubDescriptor; (* abstract *)
  133. (*
  134. * This hub class specific request overrides the hub descriptor.
  135. * Note that this request is optional. It will be stalled by the USB hub device is not supported. As all USB
  136. * device descriptors, its first byte is its length in bytes and its second bytes the descriptor type.
  137. * @param type: Descriptor type
  138. * @param index: Descriptor index
  139. * @return TRUE, if request succeeded, FALSE otherwise
  140. *)
  141. PROCEDURE SetHubDescriptor(type, index : LONGINT; buffer : Usbdi.Buffer) : BOOLEAN;
  142. BEGIN HALT(301); RETURN FALSE; END SetHubDescriptor; (* abstract *)
  143. (*
  144. * This hub class request resets a value reported in the hub status.
  145. * @param feature: Feature selector (HubLocalPower or HubOvercurrent)
  146. * @return TRUE, if request succeeded, FALSE otherwise
  147. *)
  148. PROCEDURE ClearHubFeature(feature : LONGINT) : BOOLEAN;
  149. BEGIN HALT(301); RETURN FALSE; END ClearHubFeature; (* abstract *)
  150. (*
  151. * This hub class request sets a value reported in the hub status.
  152. * @param feature: Feature selector (HubLocalPowerChange or HubOvercurrentChange)
  153. * @return TRUE, if request succeeded, FALSE otherwise
  154. *)
  155. PROCEDURE SetHubFeature(feature : LONGINT) : BOOLEAN;
  156. BEGIN HALT(301); RETURN FALSE; END SetHubFeature; (* abstract *)
  157. (*
  158. * This hub class request resets a value reported in the port status.
  159. * @param feature: Feature to be reset
  160. * @port: Port number
  161. * @return TRUE, if request succeeded, FALSE otherwise
  162. *)
  163. PROCEDURE ClearPortFeature(feature, port, selector : LONGINT) : BOOLEAN;
  164. BEGIN HALT(301); RETURN FALSE; END ClearPortFeature; (* abstract *)
  165. (*
  166. * This hub class request sets a value reported in the hub status.
  167. * @param port Port number
  168. * @param feature Feature to be resetted (HubLocalPower or HubOvercurrent)
  169. * @param selector
  170. * @return Status of the control transfer
  171. *)
  172. PROCEDURE SetPortFeature(feature, port, selector : LONGINT) : BOOLEAN;
  173. BEGIN HALT(301); RETURN FALSE; END SetPortFeature; (* abstract *)
  174. (*
  175. * This hub class request returns the current hub status and the states that have change since the
  176. * previous acknowledgment.
  177. * @param hubstatus
  178. * @return TRUE, if status request succeeded, FALSE otherwise.
  179. *)
  180. PROCEDURE GetHubStatus(VAR hubstatus : SET) : BOOLEAN;
  181. BEGIN HALT(301); RETURN FALSE; END GetHubStatus; (* abstract *)
  182. (*
  183. * This hub class request returns the current port status and the current value of the port status
  184. * change bits.
  185. * @param port Port number
  186. * @param ack Acknowledge status change bits
  187. * @return Status of the specified port
  188. *)
  189. PROCEDURE GetPortStatus(port : LONGINT; ack : BOOLEAN) : SET;
  190. BEGIN HALT(301); RETURN {}; END GetPortStatus; (* abstract *)
  191. (*
  192. * Transaction Translator (TT) control.
  193. * High-speed capable USB hub devices can operate at full- or highspeed. When connected to a highspeed host
  194. * controller, the communication between the hub device and the host is always at highspeed. When low- or fullspeed
  195. * USB devices are attached to a USB hub device operating at highspeed, the split transaction protocol is used.
  196. * The low-/fullspeed USB transactions are sent at highspeed from the host to the hub device, which has one (single-TT)
  197. * or more (multi-TT) transaction tranlators. These translate the transaction into a low-/fullspeed transaction.
  198. *)
  199. (*
  200. * This hub class specific request clears the state of the Transaction Translator (TT) bulk/control transfer after
  201. * it has been left in a busy state due to high-speed errors. This request is only defined for non-periodic endpoints.
  202. * @param dev : Low-/Fullspeed USB device
  203. * @param endpoint : Endpoint number
  204. * @param port: If the hub supports a TT per port, this is the port number of the TT that encountered the high-speed errors.
  205. * @return TRUE, if request succeeded, FALSE otherwiese
  206. *)
  207. PROCEDURE ClearTTBuffer(dev : Usb.UsbDevice; endpoint, port : LONGINT) : BOOLEAN;
  208. BEGIN
  209. RETURN FALSE;
  210. END ClearTTBuffer;
  211. (*
  212. * This hub class specific request returns the internal state of the Transaction Translator (TT) in a vendor specific format.
  213. * A TT receiving this request must have first been stopped using the StopTTRequest.
  214. * @flags Vendor specific usage
  215. * @port If the hub supports multiple TTs, specify the port number of the TT that will return TT_State. Must be one for single-TT hubs.
  216. * @return TRUE, if the request succeeded, FALSE otherwise
  217. *)
  218. PROCEDURE GetTTState(flags, port, len : LONGINT; VAR buffer : Usbdi.Buffer) : BOOLEAN;
  219. BEGIN
  220. RETURN FALSE;
  221. END GetTTState;
  222. (*
  223. * This hub class specific request returns the Transaction Translator (TT) in a hub to a known state.
  224. * After the reset is completed, the TT can resume its normal operation.
  225. * @param port: If the hub supports multiple TTs, specify the port number of the TT that is to be reset (Must be 1 for single-TT hubs).
  226. * @return TRUE, if the request succeeded, FALSE otherwise
  227. *)
  228. PROCEDURE ResetTT(port : LONGINT) : BOOLEAN;
  229. BEGIN
  230. RETURN FALSE;
  231. END ResetTT;
  232. (*
  233. * This hub class specific request stops the normal execution of the Transaction Translator (TT) so that the internal
  234. * state can be retrieved via GetTTState. This request is provided for debugging purposes.
  235. * @param port: If the hub supports multiple TTs, the port number of the TT that is being stopped must be specified (1 for single-TT hubs).
  236. * @return TRUE, if request succeeded, FALSE otherwise
  237. *)
  238. PROCEDURE StopTT(port : LONGINT) : BOOLEAN;
  239. BEGIN
  240. RETURN FALSE;
  241. END StopTT;
  242. (*
  243. * Perform initialization of USB hub device or root hub
  244. * @return TRUE, if initialization succeeded, FALSE otherwise
  245. *)
  246. PROCEDURE Initialize() : BOOLEAN;
  247. BEGIN HALT(301); RETURN FALSE; END Initialize; (* abstract *)
  248. END HubInterface;
  249. TYPE
  250. (* Integrated USB Hub Driver. *)
  251. HubDriver = OBJECT (HubInterface)
  252. VAR
  253. (* Associated USB hub device *)
  254. hub : Usb.UsbDevice;
  255. (* Information from hub descriptor *)
  256. nbrOfPorts : LONGINT; (* Number of downstream ports *)
  257. pwrOn2pwrGood : LONGINT; (* Power on to power good wait time [ms] *)
  258. powerSwitching : LONGINT; (* Supported power switching modes (NotAvailable, Global or PerPort) *)
  259. isCompound : BOOLEAN; (* Is this hub part of a compound device? *)
  260. ocProtection : LONGINT; (* Supported overcurrent protection (NotAvailable, Global or PerPort) *)
  261. thinkTime : LONGINT; (* 0..4 *)
  262. portIndicators : BOOLEAN; (* Is port indicator control support available? *)
  263. ctrlCurrent : LONGINT;
  264. deviceRemovable : POINTER TO ARRAY OF BOOLEAN;
  265. timer : Kernel.Timer;
  266. (* Enable power on the specified port (or on all ports if AllPorts is used as parameter) *)
  267. PROCEDURE EnablePortPower(port : LONGINT) : BOOLEAN;
  268. VAR i : LONGINT;
  269. BEGIN
  270. IF port = AllPorts THEN (* Only wait for power on to power good once *)
  271. IF Debug.Trace & Debug.traceHubRequests THEN Show("Enable power on all ports"); KernelLog.Ln; END;
  272. FOR i := 0 TO nbrOfPorts-1 DO
  273. IF ~SetPortFeature(PortPower, i, 0) THEN
  274. IF Debug.Level >= Debug.Errors THEN Show("Could not enable power on port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  275. RETURN FALSE;
  276. END;
  277. END;
  278. Wait(pwrOn2pwrGood);
  279. RETURN TRUE;
  280. ELSE
  281. IF Debug.Trace & Debug.traceHubRequests THEN Show("Enable power on port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  282. IF SetPortFeature(PortPower, port, 0) THEN
  283. Wait(pwrOn2pwrGood);
  284. RETURN TRUE;
  285. END;
  286. END;
  287. RETURN FALSE;
  288. END EnablePortPower;
  289. (* Disable power on the specified port *)
  290. PROCEDURE DisablePortPower(port : LONGINT) : BOOLEAN;
  291. BEGIN
  292. IF Debug.Trace & Debug.traceHubRequests THEN Show("Disable power on port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  293. RETURN ClearPortFeature(PortPower, port, 0);
  294. END DisablePortPower;
  295. (* Enable the specified port *)
  296. PROCEDURE ResetAndEnablePort(port :LONGINT) : BOOLEAN;
  297. VAR status : SET; timer : Kernel.Timer;
  298. BEGIN
  299. IF Debug.Trace & Debug.traceHubRequests THEN Show("Enable port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  300. IF SetPortFeature(PortReset, port, 0) THEN (* Hub will enable port after reset *)
  301. NEW(timer); timer.Sleep(100);
  302. status := GetPortStatus(port, FALSE);
  303. IF status * UsbHcdi.PortStatusError # {} THEN
  304. IF Debug.Level >= Debug.Errors THEN Show("Cannot get port status after enabling."); KernelLog.Ln; END;
  305. RETURN FALSE;
  306. ELSIF status * UsbHcdi.PortStatusReset # {} THEN
  307. IF Debug.Level >= Debug.Errors THEN Show("Port still in reset (after 50ms!)"); KernelLog.Ln; END;
  308. RETURN FALSE;
  309. ELSIF status * UsbHcdi.PortStatusEnabled = {} THEN
  310. IF Debug.Level >= Debug.Errors THEN Show("Could not enable port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  311. RETURN FALSE;
  312. END;
  313. ELSE
  314. RETURN FALSE;
  315. END;
  316. RETURN TRUE;
  317. END ResetAndEnablePort;
  318. (* Disable the specified port *)
  319. PROCEDURE DisablePort(port : LONGINT) : BOOLEAN;
  320. BEGIN
  321. IF Debug.Trace & Debug.traceHubRequests THEN Show("Disable port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  322. RETURN ClearPortFeature(PortEnable, port, 0);
  323. END DisablePort;
  324. (* Selectively suspend the specified port *)
  325. PROCEDURE SuspendPort(port : LONGINT) : BOOLEAN;
  326. BEGIN
  327. IF Debug.Trace & (Debug.traceHubRequests OR Debug.traceSuspend) THEN Show("Suspend port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  328. IF SetPortFeature(PortSuspend, port, 0) THEN
  329. hub.deviceAtPort[port].SetState(Usb.StateSuspended);
  330. RETURN TRUE;
  331. ELSIF Debug.Level >= Debug.Errors THEN Show("Failed to suspend port"); KernelLog.Int(port+1, 0); KernelLog.Ln;
  332. END;
  333. RETURN FALSE;
  334. END SuspendPort;
  335. (* Resume a selectively suspended port *)
  336. PROCEDURE ResumePort(port : LONGINT) : BOOLEAN;
  337. BEGIN
  338. IF Debug.Trace & (Debug.traceHubRequests OR Debug.traceSuspend) THEN Show("Resume port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  339. IF ClearPortFeature(PortSuspend, port, 0) THEN
  340. hub.deviceAtPort[port].SetState(Usb.StateConfigured);
  341. RETURN TRUE;
  342. ELSIF Debug.Level >= Debug.Errors THEN Show("Failed to resume port "); KernelLog.Int(port+1, 0); KernelLog.Ln;
  343. END;
  344. RETURN FALSE;
  345. END ResumePort;
  346. (* Are there any device drivers associated to the specified device? *)
  347. PROCEDURE DriversInstalled(dev : Usb.UsbDevice) : BOOLEAN;
  348. VAR intf : Usb.InterfaceDescriptor; i : LONGINT;
  349. BEGIN (* locking? *)
  350. FOR i := 0 TO LEN(dev.actConfiguration.interfaces)-1 DO
  351. intf := dev.actConfiguration.interfaces[i] (Usb.InterfaceDescriptor);
  352. IF intf.driver # NIL THEN RETURN TRUE; END;
  353. END;
  354. RETURN FALSE;
  355. END DriversInstalled;
  356. (* If the hub supports port indicator control, set the port indcator to Automatic, Green, Amber or Off. *)
  357. PROCEDURE Indicate(port, ledstatus : LONGINT);
  358. BEGIN
  359. IF Debug.StrongChecks THEN
  360. ASSERT((ledstatus = UsbHcdi.Automatic) OR (ledstatus =UsbHcdi. Green) OR (ledstatus = UsbHcdi.Amber) OR (ledstatus = UsbHcdi.Off));
  361. END;
  362. IF portIndicators THEN (* Port Indicator Control supported *)
  363. IF Debug.Trace & Debug.traceHubRequests THEN
  364. Show("Set port indicator of port "); KernelLog.Int(port+1, 0); KernelLog.String(" to "); KernelLog.Int(ledstatus, 0); KernelLog.Ln;
  365. END;
  366. IF SetPortFeature(PortIndicator, port, ledstatus) THEN
  367. ELSIF Debug.Level >= Debug.Errors THEN Show("Could not control port indicator."); KernelLog.Ln;
  368. END;
  369. END;
  370. END Indicate;
  371. (* How much current (mA) is available for this hub. *)
  372. PROCEDURE AvailableCurrent() : LONGINT;
  373. VAR hubstatus : SET; current : LONGINT;
  374. BEGIN
  375. current := 0;
  376. IF GetHubStatus(hubstatus) THEN
  377. IF hubstatus * HsLocalPowerLost = {} THEN (* Hub is in self-powered mode *)
  378. ELSE
  379. END;
  380. ELSE
  381. END;
  382. RETURN current;
  383. END AvailableCurrent;
  384. (* Hub may report power source changes (self-powered vs. bus-powered) and overcurrent changes (if not reported per port). *)
  385. PROCEDURE HandleHubStatusChange;
  386. VAR hubstatus : SET; ignore : BOOLEAN;
  387. BEGIN
  388. IF Debug.Trace & Debug.traceConnects THEN Show("Handling hub status change."); KernelLog.Ln; END;
  389. IF GetHubStatus(hubstatus) THEN
  390. IF hubstatus * HsLocalPowerLost # {} THEN
  391. IF Debug.Level >= Debug.Default THEN Show("Hub hast lost power supplier"); KernelLog.Ln; END;
  392. END;
  393. IF hubstatus * HsOvercurrent # {} THEN
  394. IF Debug.Level >= Debug.Default THEN Show("Hub reports overcurrent condition"); KernelLog.Ln END;
  395. END;
  396. (* Ackknowledge status changes *)
  397. IF hubstatus * HsLocalPowerSourceChange # {} THEN
  398. ignore := ClearHubFeature(HubLocalPowerChange);
  399. END;
  400. IF hubstatus * HsOvercurrentChange # {} THEN
  401. ignore := ClearHubFeature(HubOverCurrentChange);
  402. END;
  403. ELSIF Debug.Level >= Debug.Errors THEN Show("Hub status change but could not get hub status."); KernelLog.Ln;
  404. END;
  405. END HandleHubStatusChange;
  406. PROCEDURE LookForDevices;
  407. VAR i : LONGINT; trap : BOOLEAN;
  408. BEGIN
  409. IF nbrOfPorts > 0 THEN
  410. FOR i := 0 TO nbrOfPorts-1 DO (* Check and handle status of all ports *)
  411. HandlePortStatusChange(i);
  412. END;
  413. END;
  414. FINALLY
  415. IF trap & (Debug.Level >= Debug.Warnings) THEN KernelLog.String("UsbHubDriver: TRAP catched."); KernelLog.Ln; END;
  416. END LookForDevices;
  417. (* Remove device and its driver instance from the specified port *)
  418. PROCEDURE RemoveDeviceFromPort(port : LONGINT);
  419. BEGIN
  420. IF hub.deviceAtPort[port] # NIL THEN (* remove device and its driver instance from port *)
  421. hub.deviceAtPort[port].SetState(Usb.StateDisconnected);
  422. hub.deviceAtPort[port].Remove;
  423. hub.deviceAtPort[port] := NIL;
  424. END;
  425. END RemoveDeviceFromPort;
  426. (* Poll the status of this hub and look for connect changes. If a connect change occured, i.e. a USB device
  427. has been attached or detached to/from a port, call FindNewDevice or remove the device dependent data structures *)
  428. PROCEDURE HandlePortStatusChange(port : LONGINT);
  429. CONST MaxPortStatusErrors = 10;
  430. VAR dev : Usb.UsbDevice; status : SET; i : LONGINT; res : BOOLEAN;
  431. BEGIN
  432. IF Debug.Trace & Debug.traceHubRequests THEN Show("Handling port status change for port "); KernelLog.Int(port + 1, 0); KernelLog.Ln; END;
  433. status := GetPortStatus(port, TRUE);
  434. IF status * UsbHcdi.PortStatusError # {} THEN
  435. INC(hub.portErrors[port]);
  436. IF hub.portErrors[port] >= MaxPortStatusErrors THEN
  437. IF Debug.Level >= Debug.Errors THEN Show("Error: Could not get status of port "); KernelLog.Int(port + 1, 0); KernelLog.Ln; END;
  438. RemoveDeviceFromPort(port);
  439. Indicate(port, UsbHcdi.Amber);
  440. END;
  441. RETURN;
  442. ELSE
  443. hub.portErrors[port] := 0;
  444. END;
  445. IF status * UsbHcdi.PortStatusOverCurrent # {} THEN
  446. IF Debug.Level >= Debug.Default THEN Show("Warning: Overcurrent detected on port "); KernelLog.Int(port + 1, 0); KernelLog.Ln; END;
  447. END;
  448. IF status * UsbHcdi.PortStatusConnectChange # {} THEN (* Connection Status of port has changed *)
  449. IF status * UsbHcdi.PortStatusDevicePresent # {} THEN (* A device has been attached to this port *)
  450. IF Debug.Trace & Debug.traceConnects THEN Show("Looking at device at port "); KernelLog.Int(port + 1, 0); KernelLog.Ln; END;
  451. (* I've seen devices that disconnect under error conditions and then reconnect again. Therefore,
  452. we first check whether the USB system has already an attached device on the port *)
  453. IF hub.deviceAtPort[port] # NIL THEN
  454. IF Debug.Level >= Debug.Warnings THEN Show("Device already present. Remove it."); KernelLog.Ln; END;
  455. RemoveDeviceFromPort(port);
  456. END;
  457. (* Note: PortStatusConnectChange is reset by GetPortStatus() *)
  458. IF ~hub.portPermanentDisabled[port] THEN
  459. (* There mustn't be more than one enabled port with an unaddressed USB device
  460. connected to a single USB. Otherwise, multiple devices could respond to the default address 0 *)
  461. Wait(UsbHcdi.PortInsertionTime); (* >= 100ms, USBspec *)
  462. hub.controller.Acquire;
  463. res := ResetAndEnablePort(port);
  464. IF res THEN (* Try to connect to attached USB device *)
  465. i := 0;
  466. LOOP
  467. dev := GetAddressedDevice(port);
  468. IF dev # NIL THEN (* Device found *) EXIT; END;
  469. IF Debug.Trace & Debug.traceConnects THEN Show("Retrying to connect device."); KernelLog.Ln;END;
  470. res := ResetAndEnablePort(port);
  471. Wait(100 + i * 50); (* eventually the USB device reacts to slowly *)
  472. INC(i);
  473. IF i >=4 THEN EXIT END;
  474. END;
  475. IF dev = NIL THEN (* ERROR: USB device attached but not found using GetAddressedDevice *)
  476. res := DisablePort(port); (* ignore res *)
  477. hub.controller.Release;
  478. status := GetPortStatus(port, FALSE);
  479. IF status * UsbHcdi.PortStatusDevicePresent = {} THEN (* Bad timing... device is not present anymore *)
  480. Indicate(port, UsbHcdi.Off);
  481. ELSE (* There is a device attached but we can't handle it *)
  482. IF Debug.Level >= Debug.Default THEN
  483. Show("Cannot access device. Permanently disabled port "); KernelLog.Int(port+1, 0);
  484. KernelLog.String(". Replug connector of device!"); KernelLog.Ln;
  485. END;
  486. hub.portPermanentDisabled[port] := TRUE;
  487. Indicate(port, UsbHcdi.Amber);
  488. END;
  489. ELSE (* New device found & addressed *)
  490. hub.controller.Release;
  491. IF InquiryDevice(dev) THEN
  492. dev.Register(hub, port);
  493. IF Debug.Verbose THEN ShowDevice(DeviceAttached, port+1, dev); END;
  494. (* Try to install an appropriate USB device driver. If a driver is found, its Connect() procedure is called. *)
  495. Usb.drivers.ProbeDevice(dev);
  496. IF ~DriversInstalled(dev) THEN
  497. (* We don't have a driver for this device. Suspend it. *)
  498. (* res := SuspendPort(port); *)
  499. END;
  500. Indicate(port, UsbHcdi.Green);
  501. ELSE
  502. IF Debug.Level >= Debug.Default THEN Show("Failed to inquiry addressed device at port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  503. IF ~DisablePort(port) THEN (* ignore res *) END;
  504. Indicate(port, UsbHcdi.Amber);
  505. END;
  506. END;
  507. ELSE (* ERROR: Couldn't enable port *)
  508. hub.controller.Release;
  509. IF (hub.parent = hub) & hub.controller.isHighSpeed THEN
  510. (* Lowspeed or fullspeed device connected to highspeed controller root hub? *)
  511. status := GetPortStatus(port, FALSE);
  512. IF (status * UsbHcdi.PortStatusEnabled = {}) & (status * UsbHcdi.PortStatusDevicePresent # {}) THEN
  513. hub.controller.RoutePortToCompanion(port);
  514. END;
  515. ELSE
  516. IF Debug.Level >= Debug.Default THEN Show("Could not enable port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  517. hub.portPermanentDisabled[port] := TRUE;
  518. Indicate(port, UsbHcdi.Amber);
  519. END;
  520. END;
  521. ELSE
  522. IF Debug.Level >= Debug.Default THEN Show("Device connected to permanently disabled port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  523. END;
  524. ELSE (* Device has been removed from port *)
  525. IF hub.deviceAtPort[port] # NIL THEN (* Remove device and its driver instance from port *)
  526. IF Debug.Verbose THEN ShowDevice(DeviceRemoved, port, hub.deviceAtPort[port]); END;
  527. RemoveDeviceFromPort(port);
  528. END;
  529. res := DisablePort(port); (* ignore res *)
  530. hub.portPermanentDisabled[port] := FALSE; (* Reset disabled status *)
  531. hub.portErrors[port] := 0;
  532. Indicate(port, UsbHcdi.Off);
  533. END;
  534. END;
  535. (* sanity checks *)
  536. status := GetPortStatus(port, FALSE);
  537. IF status * UsbHcdi.PortStatusDevicePresent = {} THEN
  538. IF hub.deviceAtPort[port] # NIL THEN
  539. IF Debug.Level >= Debug.Warnings THEN Show("Port indicates no device present, but USB driver has one."); KernelLog.Ln; END;
  540. RemoveDeviceFromPort(port);
  541. hub.portPermanentDisabled[port] := FALSE; (* Reset disabled status *)
  542. END;
  543. END;
  544. IF status * UsbHcdi.PortStatusEnabled # {} THEN (*Port is enabled -> a device should be connected to this port *)
  545. IF hub.deviceAtPort[port] = NIL THEN
  546. IF Debug.Level >= Debug.Warnings THEN Show("Port was enabled, but USB software did not know it!"); KernelLog.Ln; END;
  547. RemoveDeviceFromPort(port);
  548. res := DisablePort(port);
  549. Indicate(port, UsbHcdi.Off);
  550. END;
  551. END;
  552. END HandlePortStatusChange;
  553. (** Traverses the bus topology towards the root hub starting at the device associated to the specified pipe. *)
  554. PROCEDURE GetTransactionTranslator(device : Usb.UsbDevice) : BOOLEAN;
  555. VAR dev : Usb.UsbDevice;
  556. BEGIN
  557. dev := device;
  558. IF dev.controller.isHighSpeed & (dev.speed # Usb.HighSpeed) THEN
  559. (* Low-/Fullspeed device connected to high-speed bus via high-speed hub device. Find the high-speed hub device. *)
  560. WHILE (dev.parent # NIL) & (dev.parent.speed # Usb.HighSpeed) DO dev := dev.parent; END;
  561. IF dev # NIL THEN
  562. device.ttAddress := dev.parent.address; device.ttPort := dev.port;
  563. IF Debug.Trace & Debug.traceConnects THEN
  564. Show("TT Address: "); KernelLog.Int(device.ttAddress, 0); KernelLog.String(", TT Port: "); KernelLog.Int(device.ttPort, 0); KernelLog.Ln;
  565. END;
  566. RETURN TRUE;
  567. ELSIF (SELF IS RootHubDriver) & (device.parent = NIL) & ~device.controller.HasCompanion() THEN
  568. device.ttAddress := 0; device.ttPort := 0;
  569. IF Debug.Level >= Debug.Warnings THEN Show("Not assigning TT for device connected to root hub"); KernelLog.Ln; END;
  570. RETURN TRUE
  571. ELSE
  572. IF Debug.Level >= Debug.Errors THEN Show("Could not find transaction translator."); KernelLog.Ln; END;
  573. RETURN FALSE;
  574. END;
  575. ELSE
  576. device.ttAddress := 0; device.ttPort := 0;
  577. RETURN TRUE;
  578. END;
  579. END GetTransactionTranslator;
  580. (*
  581. * When entering this procedure, the USB device is already in the default state, i.e. it is attached and powered.
  582. * This procedure will assign a USB device address to the device.
  583. * @param port where the USB device is attached to
  584. * @return USB device in addressed state
  585. *)
  586. PROCEDURE GetAddressedDevice(port : LONGINT) : Usb.UsbDevice;
  587. VAR
  588. dev : Usb.UsbDevice; defaultpipe : UsbHcdi.Pipe;
  589. descriptor : Usb.DeviceDescriptor;
  590. adr : LONGINT;
  591. status : SET;
  592. BEGIN
  593. IF Debug.Trace & Debug.traceConnects THEN Show("Assign address to device at port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  594. status := GetPortStatus(port, FALSE);
  595. IF status * UsbHcdi.PortStatusError # {} THEN
  596. IF Debug.Level >= Debug.Errors THEN Show("GetAddressedDevice: Cannot get status of port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  597. RETURN NIL;
  598. ELSIF status * UsbHcdi.PortStatusDevicePresent = {} THEN
  599. IF Debug.Level >= Debug.Errors THEN Show("GetAddressedDevice: Device no more present ??"); KernelLog.Ln; END;
  600. RETURN NIL;
  601. END;
  602. (* Create a new USB device object*)
  603. NEW(dev); NEW(descriptor);
  604. dev.descriptor := descriptor;
  605. dev.address := 0; (* Default address, since we did not yet assign an address to the device *)
  606. dev.controller := hub.controller;
  607. dev.parent := hub;
  608. dev.port := port;
  609. dev.SetState(Usb.StateDefault);
  610. IF status * UsbHcdi.PortStatusLowSpeed # {} THEN
  611. dev.speed := UsbHcdi.LowSpeed;
  612. ELSIF status * UsbHcdi.PortStatusFullSpeed # {} THEN
  613. dev.speed := UsbHcdi.FullSpeed;
  614. ELSIF status * UsbHcdi.PortStatusHighSpeed # {} THEN
  615. dev.speed := UsbHcdi.HighSpeed;
  616. ELSE
  617. IF Debug.Level >= Debug.Errors THEN Show("Device speed error"); KernelLog.Ln; END;
  618. RETURN NIL;
  619. END;
  620. IF ~GetTransactionTranslator(dev) THEN
  621. RETURN NIL;
  622. END;
  623. (* We link the default control pipe of the device that we're installing to the dummy default control pipe provided by the controller *)
  624. defaultpipe := hub.controller.GetDefaultPipe(dev.speed, dev.ttPort, dev.ttAddress, dev);
  625. IF defaultpipe = NIL THEN
  626. IF Debug.Level >= Debug.Errors THEN Show("Couldn't get default pipe."); KernelLog.Ln; END;
  627. RETURN NIL;
  628. END;
  629. (* Assign a USB device address to the device *)
  630. adr := hub.controller.GetFreeAddress();
  631. IF adr = 0 THEN (* Sorry, bus is full *)
  632. KernelLog.String("Usb: Cannot configure device: No free device addresses. "); KernelLog.Ln;
  633. dev.FreePipe(defaultpipe);
  634. RETURN NIL;
  635. END;
  636. dev.defaultpipe := defaultpipe;
  637. (* SetAddress will set dev.address as side-effect *)
  638. IF ~dev.SetAddress(adr) THEN
  639. dev.FreePipe(dev.defaultpipe);
  640. hub.controller.FreeAll(adr);
  641. hub.controller.FreeAddress(adr);
  642. IF Debug.Level >= Debug.Warnings THEN Show("Address Setup failed."); KernelLog.Ln;END;
  643. RETURN NIL;
  644. END;
  645. (* Note that device is now in the "address" state. The SetAddress procedure has updated the dev.address field. *)
  646. Wait(UsbHcdi.AddressRecoveryTime); (* 2ms recovery interval [USB2.0spec, p. 246] *)
  647. dev.SetState(Usb.StateAddress);
  648. (* We don't need the dummy control pipe anymore... free it up... *)
  649. dev.FreePipe(dev.defaultpipe);
  650. RETURN dev;
  651. END GetAddressedDevice;
  652. (*
  653. * When entering this procedure, the USB device is already in the addressed state, i.e. it is attached, powered and
  654. * addressed. This procedure will read in all descriptors of the device and then configure the device, so when this procedure
  655. * is left, the device is in the state configured and can be used by USB device drivers.
  656. * @param dev
  657. * @return TRUE, if operation succeeded, FALSE otherwise
  658. *)
  659. PROCEDURE InquiryDevice(dev : Usb.UsbDevice) : BOOLEAN;
  660. VAR
  661. defaultpipe, tempPipe : UsbHcdi.Pipe;
  662. buffer : Usbdi.BufferPtr;
  663. BEGIN
  664. (* Okay. we have to build the default control pipe from the device now... *)
  665. NEW(defaultpipe, dev.address, 0, dev.controller);
  666. dev.defaultpipe := defaultpipe;
  667. dev.defaultpipe.device := dev;
  668. dev.defaultpipe.completion.device := dev;
  669. dev.defaultpipe.address := dev.address;
  670. dev.defaultpipe.maxRetries := 3;
  671. dev.defaultpipe.type := UsbHcdi.PipeControl;
  672. dev.defaultpipe.maxPacketSize := 8; (* Not yet known *)
  673. dev.defaultpipe.speed := dev.speed;
  674. dev.defaultpipe.timeout := Usb.DefaultTimeout;
  675. IF GetTransactionTranslator(dev) THEN
  676. dev.defaultpipe.ttAddress := dev.ttAddress;
  677. dev.defaultpipe.ttPort := dev.ttPort;
  678. ELSE
  679. hub.controller.FreeAll(dev.address);
  680. hub.controller.FreeAddress(dev.address);
  681. RETURN FALSE;
  682. END;
  683. (* Register the default control pipe *)
  684. hub.controller.GetPipe(dev.address, 0, dev.defaultpipe);
  685. IF dev.defaultpipe = NIL THEN
  686. IF Debug.Level >= Debug.Errors THEN Show("InquiryDevice: Could not register the default control pipe"); KernelLog.Ln; END;
  687. hub.controller.FreeAll(dev.address);
  688. hub.controller.FreeAddress(dev.address);
  689. RETURN FALSE;
  690. END;
  691. (* We are only allowed to read 8 bytes until now - otherwise there could happen a babble error *)
  692. NEW(buffer, 8);
  693. IF ~dev.GetDescriptor(DescriptorDevice, 0, 0, 8, buffer) THEN
  694. IF Debug.Level >= Debug.Errors THEN Show("InquiryDevice: Read first 8 bytes of device descriptor failed."); KernelLog.Ln; END;
  695. hub.controller.FreeAll(dev.address);
  696. hub.controller.FreeAddress(dev.address);
  697. RETURN FALSE;
  698. END;
  699. dev.defaultpipe.maxPacketSize := ORD(buffer[7]);
  700. (* We don't need the dummy control pipe anymore... free it up... *)
  701. tempPipe := dev.defaultpipe;
  702. dev.FreePipe(dev.defaultpipe);
  703. tempPipe.device := dev; (* has been removed by FreePipe *)
  704. hub.controller.GetPipe(dev.address, 0, tempPipe);
  705. IF tempPipe = NIL THEN
  706. IF Debug.Level >= Debug.Errors THEN Show("InquiryDevice: Could not register the default control pipe"); KernelLog.Ln; END;
  707. hub.controller.FreeAll(dev.address);
  708. hub.controller.FreeAddress(dev.address);
  709. RETURN FALSE;
  710. END;
  711. dev.defaultpipe := tempPipe;
  712. dev.defaultpipe.completion.device := dev;
  713. (* okay, device is in adressed state... we now parse the device descriptor *)
  714. IF ~dev.GetDeviceDescriptor() OR ~dev.GetConfigurations()THEN
  715. hub.controller.FreeAll(dev.address);
  716. hub.controller.FreeAddress(dev.address);
  717. IF Debug.Level >= Debug.Errors THEN Show("Parsing descriptors failed."); KernelLog.Ln; END;
  718. RETURN FALSE;
  719. END;
  720. (* If the attached device is USB2.0 complaint, we also load and parse the Device Qualifier and
  721. the Other Speed Configurations *)
  722. IF dev.descriptor.bcdUSB >= 0200H THEN
  723. IF Debug.Trace & Debug.traceConnects THEN Show("Get device qualifier."); KernelLog.Ln; END;
  724. IF ~dev.GetDeviceQualifier() THEN
  725. IF Debug.Level >= Debug.Errors THEN Show("Couldn't get device qualifier."); KernelLog.Ln; END;
  726. ELSIF dev.GetOtherSpeedConfigurations() THEN
  727. IF ~dev.controller.isHighSpeed THEN
  728. KernelLog.String("UsbHubDriver: Warning: Connected high-speed capable device to low-/full-speed controller."); KernelLog.Ln;
  729. END;
  730. ELSE
  731. IF Debug.Level >= Debug.Errors THEN Show("Couldn't get other speed configurations"); KernelLog.Ln; END;
  732. END;
  733. END;
  734. (* Check whether topology constrains are met and enough power is available *)
  735. IF ~ValidTopology(dev, hub) THEN
  736. hub.controller.FreeAll(dev.address);
  737. hub.controller.FreeAddress(dev.address);
  738. Show("Topology constraints violated. Cannot configure device."); KernelLog.Ln;
  739. RETURN FALSE;
  740. END;
  741. IF ~EnoughPower(dev, hub) THEN
  742. hub.controller.FreeAll(dev.address);
  743. hub.controller.FreeAddress(dev.address);
  744. Show("Not enough power available. Cannot configure device."); KernelLog.Ln;
  745. RETURN FALSE;
  746. END;
  747. (* Enough bandwidth available? *)
  748. (* Set Configuration *)
  749. IF ~dev.SetConfiguration(0) THEN
  750. hub.controller.FreeAll(dev.address);
  751. hub.controller.FreeAddress(dev.address);
  752. IF Debug.Level >= Debug.Errors THEN Show("Could not set configuration"); KernelLog.Ln; END;
  753. RETURN FALSE;
  754. END;
  755. dev.SetState(Usb.StateConfigured);
  756. (* IF AllowSuspend THEN (* Enable remote wakeup if supported. *)
  757. IF ~dev.hubFlag & (dev.descriptor.bDeviceClass # 09H) & dev.actConfiguration(Usb.ConfigurationDescriptor).remoteWakeup THEN
  758. IF ~dev.SetFeature(Device, 0, Usb.FsDeviceRemoteWakeup) THEN
  759. IF Debug THEN Show("Warning: Could not enable remote wakeup."); END;
  760. END;
  761. END;
  762. END; *)
  763. (* Get sManufacturer, sProduct and sSerialNumber strings & interface/configurations descriptors *)
  764. Usb.GetStrings(dev);
  765. RETURN TRUE;
  766. END InquiryDevice;
  767. PROCEDURE ParseHubDescriptor(buffer : Usbdi.Buffer) : BOOLEAN;
  768. VAR i : LONGINT;
  769. BEGIN
  770. IF (LEN(buffer) < 2) OR (ORD(buffer[0]) < 7) OR (ORD(buffer[1]) # DescriptorHub) THEN RETURN FALSE; END;
  771. nbrOfPorts := ORD(buffer[2]);
  772. i := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, ORD(buffer[3])) * {0..1});
  773. CASE i OF
  774. 0 : powerSwitching := Global;
  775. |1 : powerSwitching := PerPort;
  776. ELSE
  777. powerSwitching := NotAvailable;
  778. END;
  779. IF SYSTEM.VAL(SET, ORD(buffer[3])) * {2} # {} THEN isCompound := TRUE; END;
  780. IF SYSTEM.VAL(SET, ORD(buffer[3])) * {7} # {} THEN portIndicators := TRUE; END;
  781. i := SYSTEM.VAL(LONGINT, LSH(SYSTEM.VAL(SET, ORD(buffer[3])) * {3..4}, -3));
  782. CASE i OF
  783. 0 : ocProtection := Global;
  784. |1 : ocProtection := PerPort;
  785. ELSE
  786. ocProtection := NotAvailable;
  787. END;
  788. thinkTime := SYSTEM.VAL(LONGINT, LSH(SYSTEM.VAL(SET, ORD(buffer[3])) * {3..4}, -3));
  789. pwrOn2pwrGood := ORD(buffer[5]) * 2; (* PowerOn 2 PowerGood measured in 2ms steps *)
  790. ctrlCurrent := ORD(buffer[6]);
  791. (* IF (ORD(buffer[2]) - 7) > (nbrOfPorts DIV 8 + 1) THEN
  792. NEW(deviceRemovable, nbrOfPorts);
  793. FOR i := 0 TO nbrOfPorts - 1 DO
  794. IF (SYSTEM.VAL(SET, ORD(buffer[7 + i DIV 8])) * SYSTEM.VAL(SET, i MOD 8) = {}) THEN
  795. deviceRemovable[i] := TRUE;
  796. END;
  797. END;
  798. END; *)
  799. RETURN TRUE;
  800. END ParseHubDescriptor;
  801. (* Load and parse the hub descriptor, power on all ports *)
  802. PROCEDURE Connect() : BOOLEAN;
  803. VAR buffer : Usbdi.BufferPtr; len : LONGINT;
  804. BEGIN
  805. hub := device (Usb.UsbDevice);
  806. (* First get the first 8 bytes of the hub descriptor to get its length and then load the full length hub desriptor *)
  807. NEW(buffer, 2);
  808. IF ~GetHubDescriptor(DescriptorHub, 0, 2, buffer) THEN
  809. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbHubDriver: Could not get first two bytes of hub descriptor."); KernelLog.Ln; END;
  810. RETURN FALSE;
  811. END;
  812. len := ORD(buffer[0]); NEW(buffer, len);
  813. IF ~GetHubDescriptor(DescriptorHub, 0, SYSTEM.VAL(LONGINT, len), buffer) THEN
  814. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbHubDriver: Could not get hub descriptor."); KernelLog.Ln; END;
  815. RETURN FALSE;
  816. END;
  817. IF ~ParseHubDescriptor(buffer) THEN
  818. IF Debug.Level >= Debug.Errors THEN KernelLog.String("UsbHubDriver: Failed to parse hub descriptor."); KernelLog.Ln; END;
  819. RETURN FALSE;
  820. END;
  821. hub.hubFlag := TRUE;
  822. hub.nbrOfPorts := nbrOfPorts;
  823. NEW(hub.deviceAtPort, nbrOfPorts);
  824. NEW(hub.portPermanentDisabled, nbrOfPorts);
  825. NEW(hub.portErrors, nbrOfPorts);
  826. IF Debug.Trace & Debug.traceInfo THEN ShowInfo; END;
  827. IF ~EnablePortPower(AllPorts) THEN
  828. IF Debug.Level >= Debug.Errors THEN Show("Error: Could not enable port power"); KernelLog.Ln; END;
  829. RETURN FALSE;
  830. END;
  831. IF Debug.Verbose THEN Show(""); KernelLog.Int(nbrOfPorts, 0); KernelLog.String(" ports detected."); KernelLog.Ln; END;
  832. RETURN Initialize();
  833. END Connect;
  834. PROCEDURE ValidTopology(dev, parent : Usb.UsbDevice) : BOOLEAN;
  835. VAR segments : LONGINT; temp : Usb.UsbDevice;
  836. BEGIN (* Should lock topology !! *)
  837. IF dev.hubFlag THEN
  838. (* Count cable segments between dev and the host *)
  839. temp := dev;
  840. WHILE temp.parent # dev DO
  841. INC(segments);
  842. temp := temp.parent;
  843. END;
  844. (* No more than 6 cable segments allowed between device and host (USB2.0, p ??) *)
  845. IF segments > 6 THEN
  846. Show("Bus topology constraint not met: maximum of 6 cable segment between device and host."); KernelLog.Ln;
  847. RETURN FALSE;
  848. END;
  849. END;
  850. RETURN TRUE;
  851. END ValidTopology;
  852. (* Can the hub parent provide enough power for the device dev ? *)
  853. PROCEDURE EnoughPower(dev, parent : Usb.UsbDevice) : BOOLEAN;
  854. VAR status : SET;
  855. BEGIN
  856. IF dev.GetStatus(Device, 0, status) THEN
  857. (* TODO: Implement *)
  858. (* Unfortunately, most hubs claim to be self-powered even when it's not the case... *)
  859. IF status * Usb.SelfPowered # {} THEN
  860. IF Debug.Trace & Debug.traceConnects THEN Show(""); dev.ShowName; KernelLog.String(" is self-powered."); KernelLog.Ln; END;
  861. ELSE
  862. IF Debug.Trace & Debug.traceConnects THEN Show(""); dev.ShowName; KernelLog.String(" is bus-powered."); KernelLog.Ln; END;
  863. END;
  864. ELSE
  865. IF Debug.Level >= Debug.Errors THEN Show("GetStatus request failed."); KernelLog.Ln; END;
  866. END;
  867. RETURN TRUE;
  868. END EnoughPower;
  869. PROCEDURE Disconnect;
  870. BEGIN
  871. IF Debug.Verbose THEN Show(" disconnected."); KernelLog.Ln;END;
  872. END Disconnect;
  873. PROCEDURE Wait(ms : LONGINT);
  874. BEGIN {EXCLUSIVE}
  875. timer.Sleep(ms)
  876. END Wait;
  877. PROCEDURE &New*;
  878. BEGIN
  879. NEW(timer); (* Used by Wait *)
  880. END New;
  881. PROCEDURE ShowDevice(mode, port : LONGINT; dev : Usb.UsbDevice);
  882. BEGIN
  883. IF Debug.StrongChecks THEN ASSERT((dev # NIL) & ((mode = DeviceAttached) OR (mode = DeviceRemoved))); END;
  884. KernelLog.String("UsbHubDriver: "); dev.ShowName;
  885. IF mode = DeviceAttached THEN
  886. KernelLog.String(" attached to "); KernelLog.String(hub.controller.name); KernelLog.String(" port ");
  887. KernelLog.Int(port, 0); KernelLog.String("."); KernelLog.Ln;
  888. ELSE
  889. KernelLog.String(" has been detached."); KernelLog.Ln;
  890. END;
  891. END ShowDevice;
  892. PROCEDURE ShowInfo;
  893. VAR i : LONGINT;
  894. BEGIN
  895. IF Debug.Trace THEN
  896. Show(" Capabilities:"); KernelLog.Ln;
  897. KernelLog.String(" Compound device: "); IF isCompound THEN KernelLog.String("Yes"); ELSE KernelLog.String("No"); END;
  898. KernelLog.String(", Port indicator control: "); IF portIndicators THEN KernelLog.String("Yes"); ELSE KernelLog.String("No"); END;
  899. KernelLog.String(", Power switching support: ");
  900. IF powerSwitching = NotAvailable THEN KernelLog.String("n/a");
  901. ELSIF powerSwitching = Global THEN KernelLog.String("Global");
  902. ELSIF powerSwitching = PerPort THEN KernelLog.String("Per port");
  903. ELSE KernelLog.String("Error: "); KernelLog.Int(powerSwitching, 0);
  904. END;
  905. KernelLog.String(", Overcurrent protection: ");
  906. IF ocProtection = NotAvailable THEN KernelLog.String("n/a");
  907. ELSIF ocProtection = Global THEN KernelLog.String("Global");
  908. ELSIF ocProtection = PerPort THEN KernelLog.String("Per port");
  909. ELSE KernelLog.String("Error: "); KernelLog.Int(ocProtection, 0);
  910. END;
  911. KernelLog.Ln;
  912. KernelLog.String(" Power On 2 Power Good: "); KernelLog.Int(pwrOn2pwrGood, 0); KernelLog.String(" ms");
  913. KernelLog.String(", Control logic current: "); KernelLog.Int(ctrlCurrent, 0); KernelLog.String(" mA");
  914. KernelLog.String(", Think time: "); KernelLog.Int(thinkTime, 0); KernelLog.String(" ms"); KernelLog.Ln;
  915. KernelLog.String(" Number of downstream ports: "); KernelLog.Int(nbrOfPorts, 0); KernelLog.Ln;
  916. FOR i := 0 TO nbrOfPorts-1 DO
  917. KernelLog.String(" Port "); KernelLog.Int(i, 0); KernelLog.String(": ");
  918. IF (deviceRemovable # NIL) & deviceRemovable[i] THEN KernelLog.String("[Removable]"); END;
  919. UsbHcdi.ShowPortStatus(GetPortStatus(i, FALSE));
  920. KernelLog.Ln;
  921. END;
  922. KernelLog.Ln;
  923. END;
  924. END ShowInfo;
  925. (* Displays message containing a description of this hub and the specified text to kernel log *)
  926. PROCEDURE Show(CONST text : ARRAY OF CHAR);
  927. BEGIN
  928. KernelLog.String("UsbHubDriver: Hub "); hub.ShowName;
  929. KernelLog.String(" attached to "); KernelLog.String(hub.controller.name); KernelLog.String(" port ");
  930. KernelLog.Int(hub.port + 1, 0); KernelLog.String(": "); KernelLog.String(text);
  931. END Show;
  932. END HubDriver;
  933. TYPE
  934. (* Implementation of the USB hub device specific parts of the Hub Driver *)
  935. UsbHubDriver = OBJECT(HubDriver)
  936. VAR
  937. (* Hub device status pipe for status notifications *)
  938. statusPipe : Usbdi.Pipe;
  939. statusBuffer : Usbdi.BufferPtr;
  940. statusPipeRetries : LONGINT;
  941. (* This hub class specific request returns the hub descriptor. *)
  942. PROCEDURE GetHubDescriptor(type, index, length : LONGINT; VAR buffer : Usbdi.Buffer) : BOOLEAN;
  943. BEGIN
  944. ASSERT(length >= 2);
  945. RETURN (hub.defaultpipe.Request(ToHost + Class + Device, GetDescriptor, index + type*100H, 0, length, buffer) = Usbdi.Ok) &
  946. (ORD(buffer[1]) = type);
  947. END GetHubDescriptor;
  948. (* This hub class specific request overrides the hub descriptor. *)
  949. PROCEDURE SetHubDescriptor(type, index : LONGINT; buffer : Usbdi.Buffer) : BOOLEAN;
  950. BEGIN
  951. ASSERT((LEN(buffer) >= 2) & (ORD(buffer[0]) = LEN(buffer)) & (ORD(buffer[1]) = type));
  952. RETURN hub.defaultpipe.Request(ToDevice + Class + Device, SetDescriptor, index + type*100H, 0, LEN(buffer), buffer) = Usbdi.Ok;
  953. END SetHubDescriptor;
  954. (* This hub class request resets a value reported in the hub status. *)
  955. PROCEDURE ClearHubFeature(feature : LONGINT) : BOOLEAN;
  956. BEGIN
  957. IF Debug.StrongChecks THEN ASSERT((feature = HubLocalPowerChange) OR (feature = HubOverCurrentChange)); END; (* Valid feature selector *)
  958. IF Debug.Trace & Debug.traceHubRequests THEN Show("Clear hub feature "); KernelLog.Int(feature, 0); KernelLog.Ln; END;
  959. RETURN hub.defaultpipe.Request(ToDevice + Class + Device, ClearFeature, feature, 0, 0, Usbdi.NoData) = Usbdi.Ok;
  960. END ClearHubFeature;
  961. (* This hub class request sets a value reported in the hub status. *)
  962. PROCEDURE SetHubFeature(feature : LONGINT) : BOOLEAN;
  963. BEGIN
  964. IF Debug.StrongChecks THEN ASSERT((feature = HubLocalPowerChange) OR (feature = HubOverCurrentChange)); END; (* Valid feature selector *)
  965. IF Debug.Trace & Debug.traceHubRequests THEN Show("Set hub feature "); KernelLog.Int(feature, 0); KernelLog.Ln; END;
  966. RETURN hub.defaultpipe.Request(ToDevice + Class + Device, SetFeature, feature, 0, 0, Usbdi.NoData) = Usbdi.Ok;
  967. END SetHubFeature;
  968. (* This hub class request resets a value reported in the port status. *)
  969. PROCEDURE ClearPortFeature(feature, port, selector : LONGINT) : BOOLEAN;
  970. BEGIN
  971. IF Debug.StrongChecks THEN
  972. ASSERT(((feature # PortTest) & (feature # PortIndicator)) OR (selector = 0));
  973. ASSERT((feature > 0) & (feature <= 22) & (feature # PortConnection)); (* Valid feature selector *)
  974. END;
  975. IF Debug.Trace & Debug.traceHubRequests THEN Show("Port "); KernelLog.Int(port + 1, 0); KernelLog.String(": Clear feature "); KernelLog.Int(feature, 0); KernelLog.Ln; END;
  976. RETURN hub.defaultpipe.Request(ToDevice + Class + Other, ClearFeature, feature, (port + 1) + LSH(selector, 8), 0, Usbdi.NoData) = Usbdi.Ok;
  977. END ClearPortFeature;
  978. (* This hub class request sets a value reported in the hub status. *)
  979. PROCEDURE SetPortFeature(feature, port, selector : LONGINT) : BOOLEAN;
  980. BEGIN
  981. IF Debug.StrongChecks THEN
  982. ASSERT(((feature = PortTest) OR (feature = PortIndicator)) OR (selector = 0));
  983. ASSERT((feature > 0) & (feature <= 22) & (feature # PortConnection)); (* Valid feature selector *)
  984. END;
  985. IF Debug.Trace & Debug.traceHubRequests THEN Show("Port "); KernelLog.Int(port + 1, 0); KernelLog.String(": Set feature "); KernelLog.Int(feature, 0); KernelLog.Ln; END;
  986. RETURN hub.defaultpipe.Request(ToDevice + Class + Other, SetFeature, feature, (port + 1) + LSH(selector, 8), 0, Usbdi.NoData) = Usbdi.Ok;
  987. END SetPortFeature;
  988. (* This hub class request returns the current hub status and the states that have change since the previous acknowledgment. *)
  989. PROCEDURE GetHubStatus(VAR hubstatus : SET) : BOOLEAN;
  990. VAR buffer : Usbdi.BufferPtr;
  991. BEGIN
  992. IF Debug.Trace & Debug.traceHubRequests THEN Show("Get Hub Status."); KernelLog.Ln; END;
  993. NEW(buffer, 4);
  994. IF hub.defaultpipe.Request(ToHost + Class + Device, GetStatus, 0, 0, 4, buffer) = Usbdi.Ok THEN
  995. hubstatus := SYSTEM.VAL(SET, SYSTEM.GET32(UsbBuffers.GetDataAddress(buffer)));
  996. RETURN TRUE;
  997. END;
  998. RETURN FALSE;
  999. END GetHubStatus;
  1000. (* This hub class request returns the current port status and the current value of the port status change bits. *)
  1001. PROCEDURE GetPortStatus(port : LONGINT; ack : BOOLEAN) : SET;
  1002. VAR buffer : Usbdi.BufferPtr; s, portstatus : SET;
  1003. BEGIN
  1004. IF Debug.StrongChecks THEN ASSERT(port >= 0); END;
  1005. IF Debug.Trace & Debug.traceHubRequests THEN
  1006. Show("Get port status of port "); KernelLog.Int(port + 1, 0); IF ack THEN KernelLog.String(" (ACK)"); END; KernelLog.Ln;
  1007. END;
  1008. NEW(buffer, 4);
  1009. IF hub.defaultpipe.Request(ToHost + Class + Other, GetStatus, 0, port+1, 4, buffer) = Usbdi.Ok THEN
  1010. s := SYSTEM.VAL(SET, SYSTEM.GET32(UsbBuffers.GetDataAddress(buffer)));
  1011. IF ack & (s * PsChangeMask # {}) THEN (* Acknowledge the changes *)
  1012. IF s * PsConnectStatusChange # {} THEN
  1013. IF ~ClearPortFeature(PortConnectionChange, port, 0) THEN
  1014. RETURN UsbHcdi.PortStatusError;
  1015. END;
  1016. END;
  1017. IF s * PsPortEnabledChange # {} THEN
  1018. IF ~ClearPortFeature(PortEnableChange, port, 0) THEN
  1019. RETURN UsbHcdi.PortStatusError;
  1020. END;
  1021. END;
  1022. IF s * PsSuspendChange # {} THEN
  1023. IF ~ClearPortFeature(PortSuspendChange, port, 0) THEN
  1024. RETURN UsbHcdi.PortStatusError;
  1025. END;
  1026. END;
  1027. IF s * PsOvercurrentChange # {} THEN
  1028. IF ~ClearPortFeature(PortOverCurrentChange, port, 0) THEN
  1029. RETURN UsbHcdi.PortStatusError;
  1030. END;
  1031. END;
  1032. IF s * PsResetChange # {} THEN
  1033. IF ~ClearPortFeature(PortResetChange, port, 0) THEN
  1034. RETURN UsbHcdi.PortStatusError;
  1035. END;
  1036. END;
  1037. END;
  1038. IF s * PsCurrentConnectStatus # {} THEN
  1039. portstatus := portstatus + UsbHcdi.PortStatusDevicePresent;
  1040. IF s * PsPortEnabled # {} THEN
  1041. portstatus := portstatus + UsbHcdi.PortStatusEnabled;
  1042. IF s * PsLowSpeed # {} THEN
  1043. portstatus := portstatus + UsbHcdi.PortStatusLowSpeed;
  1044. ELSIF s * PsHighSpeed # {} THEN
  1045. portstatus := portstatus + UsbHcdi.PortStatusHighSpeed;
  1046. ELSE
  1047. portstatus := portstatus + UsbHcdi.PortStatusFullSpeed;
  1048. END;
  1049. END;
  1050. END;
  1051. IF s * PsSuspend # {} THEN portstatus := portstatus + UsbHcdi.PortStatusSuspended; END;
  1052. IF s * PsOverCurrent # {} THEN portstatus := portstatus + UsbHcdi.PortStatusOverCurrent; END;
  1053. IF s * PsReset # {} THEN portstatus := portstatus + UsbHcdi.PortStatusReset; END;
  1054. IF s * PsPortPower # {} THEN portstatus := portstatus + UsbHcdi.PortStatusPowered; END;
  1055. IF s * PsPortTestMode # {} THEN portstatus := portstatus + UsbHcdi.PortStatusTestControl; END;
  1056. IF s * PsPortIndicators # {} THEN portstatus := portstatus + UsbHcdi.PortStatusIndicatorControl; END;
  1057. IF s * PsConnectStatusChange # {} THEN portstatus := portstatus + UsbHcdi.PortStatusConnectChange; END;
  1058. IF s * PsPortEnabledChange # {} THEN portstatus := portstatus + UsbHcdi.PortStatusEnabledChange; END;
  1059. IF s * PsSuspendChange # {} THEN portstatus := portstatus + UsbHcdi.PortStatusSuspendChange; END;
  1060. IF s * PsOvercurrentChange # {} THEN portstatus := portstatus + UsbHcdi.PortStatusOverCurrentChange; END;
  1061. IF s * PsResetChange # {} THEN portstatus := portstatus + UsbHcdi.PortStatusResetChange; END;
  1062. IF Debug.Trace & Debug.traceHubRequests THEN
  1063. Show("Status of port "); KernelLog.Int(port + 1, 0); UsbHcdi.ShowPortStatus(portstatus); KernelLog.Ln;
  1064. END;
  1065. RETURN portstatus;
  1066. ELSE
  1067. IF Debug.Level >= Debug.Errors THEN Show("Can't get port status of port "); KernelLog.Int(port+1, 0); KernelLog.Ln; END;
  1068. RETURN UsbHcdi.PortStatusError;
  1069. END;
  1070. END GetPortStatus;
  1071. (*
  1072. * This handler is called when the hub's interrupt IN status pipe reports a change of either
  1073. * the hub status or the status of a hub port.
  1074. *)
  1075. PROCEDURE HandleStatusChange(status : Usbdi.Status; actLen : LONGINT);
  1076. VAR ignore : Usbdi.Status; i, port : LONGINT;
  1077. BEGIN
  1078. IF Debug.Trace & Debug.traceConnects THEN
  1079. Show("Hub reports status change: "); FOR i := 0 TO LEN(statusBuffer)-1 DO KernelLog.Hex(ORD(statusBuffer[i]), -2); END; KernelLog.Ln;
  1080. END;
  1081. IF (status = Usbdi.Ok) OR ((status = Usbdi.ShortPacket) & (actLen > 0)) THEN
  1082. IF SYSTEM.VAL(SET, statusBuffer[0]) * {0} # {} THEN (* Hub status changed *)
  1083. IF Debug.Trace & Debug.traceConnects THEN Show("Hub status changed."); END;
  1084. statusBuffer[0] := SYSTEM.VAL(CHAR, SYSTEM.VAL(SET, statusBuffer[0]) - {0}); (* Clear hub status change bit *)
  1085. HandleHubStatusChange;
  1086. END;
  1087. (* Look for port status changes *)
  1088. FOR i := 0 TO actLen-1 DO
  1089. FOR port := 0 TO 7 DO
  1090. IF SYSTEM.VAL(SET, statusBuffer[i]) * {port} # {} THEN
  1091. HandlePortStatusChange(port + i * 8 - 1);
  1092. END;
  1093. END;
  1094. END;
  1095. ignore := statusPipe.Transfer(statusPipe.maxPacketSize, 0, statusBuffer);
  1096. statusPipeRetries := 0;
  1097. ELSE
  1098. IF statusPipeRetries > StatusPipeMaxRetries THEN
  1099. IF Debug.Level >= Debug.Errors THEN Show("Status pipe error "); UsbHcdi.ShowStatus(status); KernelLog.Ln; END;
  1100. RETURN; (* give up *)
  1101. END;
  1102. IF (status = Usbdi.Stalled) THEN
  1103. IF ~statusPipe.ClearHalt() THEN
  1104. IF Debug.Level >= Debug.Errors THEN Show("Could not recover from status pipe error."); KernelLog.Ln; END;
  1105. RETURN;
  1106. END;
  1107. ELSIF (status = Usbdi.Disconnected) THEN
  1108. RETURN;
  1109. END;
  1110. ignore := statusPipe.Transfer(statusPipe.maxPacketSize, 0, statusBuffer);
  1111. INC(statusPipeRetries);
  1112. END;
  1113. END HandleStatusChange;
  1114. (* USB hub device specific initialization *)
  1115. PROCEDURE Initialize() : BOOLEAN;
  1116. VAR endpoint : Usbdi.EndpointDescriptor; ignore : Usbdi.Status;
  1117. BEGIN
  1118. (* Look for the hub's interrupt endpoint which is used to communicate status changes *)
  1119. endpoint := hub.actConfiguration.interfaces[0].endpoints[0];
  1120. ASSERT(endpoint.type = Usbdi.InterruptIn);
  1121. statusPipe := hub.GetPipe(endpoint.bEndpointAddress);
  1122. IF statusPipe = NIL THEN
  1123. IF Debug.Level >= Debug.Errors THEN Show("Could not establish status pipe."); KernelLog.Ln; END;
  1124. RETURN FALSE;
  1125. END;
  1126. NEW(statusBuffer, statusPipe.maxPacketSize);
  1127. statusPipe.SetTimeout(0); (* Non-blocking pipe *)
  1128. statusPipe.SetCompletionHandler(HandleStatusChange);
  1129. ignore := statusPipe.Transfer(statusPipe.maxPacketSize, 0, statusBuffer);
  1130. RETURN TRUE;
  1131. END Initialize;
  1132. (*
  1133. * This hub class specific request clears the state of the Transaction Translator (TT) bulk/control transfer after
  1134. * it has been left in a busy state due to high-speed errors. This request is only defined for non-periodic endpoints.
  1135. *)
  1136. PROCEDURE ClearTTBuffer(dev : Usb.UsbDevice; endpoint, port : LONGINT) : BOOLEAN;
  1137. VAR intf : Usb.InterfaceDescriptor; endp : Usb.EndpointDescriptor; wValue : SET; i, e : LONGINT;
  1138. BEGIN
  1139. IF Debug.StrongChecks THEN ASSERT((dev.speed # Usb.HighSpeed) & (dev.parent.speed = Usb.HighSpeed)); END;
  1140. (* Get the endpoint *)
  1141. LOOP (* Search all interfaces *)
  1142. IF i > dev.actConfiguration.bNumInterfaces-1 THEN EXIT END;
  1143. intf := dev.actConfiguration.interfaces[i] (Usb.InterfaceDescriptor);
  1144. FOR e := 0 TO LEN(intf.endpoints)-1 DO (* Search all endpoints *)
  1145. IF intf.endpoints[e].bEndpointAddress = endpoint THEN (* Endpoint found *)
  1146. endp := intf.endpoints[e] (Usb.EndpointDescriptor);
  1147. END;
  1148. END;
  1149. IF endp # NIL THEN EXIT END;
  1150. INC(i);
  1151. END;
  1152. IF endp = NIL THEN (* Endpoint not found *) RETURN FALSE END;
  1153. IF (endp.bmAttributes * {0,1} # {}) OR (endp.bmAttributes * {0,1} # {1}) THEN
  1154. IF Debug.Level >= Debug.Warnings THEN Show("ClearTTBuffer error: Only allowed for non-periodic endpoints"); KernelLog.Ln; END;
  1155. RETURN FALSE;
  1156. END;
  1157. (* wValue: {0..3}: Endpoint Number, {4..10}: Device Address, {11..12}: Endpoint Type, {13..13}: Reserved, {15}: Endpoint Direction *)
  1158. wValue := SYSTEM.VAL(SET, endp.bEndpointAddress) * {0..3} + LSH(SYSTEM.VAL(SET, dev.address), 4) * {4..10};
  1159. wValue := wValue + LSH(endp.bmAttributes ,11) * {11..12} + LSH(SYSTEM.VAL(SET, endp.bEndpointAddress) * {7}, 8);
  1160. RETURN hub.defaultpipe.Request(ToDevice + Class + Other, ClearTtBuffer, SYSTEM.VAL(LONGINT, wValue), (port + 1), 0, Usbdi.NoData) = Usbdi.Ok;
  1161. END ClearTTBuffer;
  1162. (*
  1163. * This hub class specific request returns the internal state of the Transaction Translator (TT) in a vendor specific format.
  1164. * A TT receiving this request must have first been stopped using the StopTTRequest.
  1165. *)
  1166. PROCEDURE GetTTState(flags, port, len : LONGINT; VAR buffer : Usbdi.Buffer) : BOOLEAN;
  1167. BEGIN
  1168. RETURN hub.defaultpipe.Request(ToDevice + Class + Other, GetTtState, flags, (port + 1), len, buffer) = Usbdi.Ok;
  1169. END GetTTState;
  1170. (*
  1171. * This hub class specific request returns the Transaction Translator (TT) in a hub to a known state.
  1172. * After the reset is completed, the TT can resume its normal operation.
  1173. *)
  1174. PROCEDURE ResetTT(port : LONGINT) : BOOLEAN;
  1175. BEGIN
  1176. RETURN hub.defaultpipe.Request(ToDevice + Class + Other, ResetTt, 0, (port + 1), 0, Usbdi.NoData) = Usbdi.Ok;
  1177. END ResetTT;
  1178. (*
  1179. * This hub class specific request stops the normal execution of the Transaction Translator (TT) so that the internal
  1180. * state can be retrieved via GetTTState. This request is provided for debugging purposes.
  1181. *)
  1182. PROCEDURE StopTT(port : LONGINT) : BOOLEAN;
  1183. BEGIN
  1184. RETURN hub.defaultpipe.Request(ToDevice + Class + Other, StopTt, 0, (port + 1), 0, Usbdi.NoData) = Usbdi.Ok;
  1185. END StopTT;
  1186. END UsbHubDriver;
  1187. TYPE
  1188. (* Implementation of the USB root hub specific parts of the Hub Driver *)
  1189. RootHubDriver = OBJECT (HubDriver)
  1190. VAR
  1191. (* Root hub management *)
  1192. next: RootHubDriver;
  1193. (* Active object handling *)
  1194. timerRH : Kernel.Timer;
  1195. alive, dead, statusChange : BOOLEAN;
  1196. pollingInterval : LONGINT;
  1197. (* Will be true when Connect() returns. Used to synchronize active body *)
  1198. initialized : BOOLEAN;
  1199. (* Get the emulated hub descriptor. Ignore type and index parameters. *)
  1200. PROCEDURE GetHubDescriptor(type, index, length : LONGINT; VAR buffer : Usbdi.Buffer) : BOOLEAN;
  1201. VAR i : LONGINT; hd : UsbHcdi.HubDescriptor;
  1202. BEGIN
  1203. IF Debug.StrongChecks THEN ASSERT(LEN(buffer) <= length); END;
  1204. hd := device(Usb.UsbDevice).controller.GetHubDescriptor();
  1205. IF hd = NIL THEN RETURN FALSE END;
  1206. IF length > LEN(hd) THEN length := LEN(hd); END;
  1207. FOR i := 0 TO length-1 DO buffer[i] := hd[i]; END;
  1208. RETURN TRUE;
  1209. END GetHubDescriptor;
  1210. (* Overwrites the emulated hub descriptor. Ignore type and index paramters. *)
  1211. PROCEDURE SetHubDescriptor(type, index : LONGINT; buffer : Usbdi.Buffer) : BOOLEAN;
  1212. VAR i : LONGINT; hd : UsbHcdi.HubDescriptor;
  1213. BEGIN
  1214. IF Debug.StrongChecks THEN ASSERT((LEN(buffer)>=8) & (ORD(buffer[0])=LEN(buffer)) & (ORD(buffer[1])=type)); END;
  1215. NEW(hd, LEN(buffer));
  1216. FOR i := 0 TO LEN(buffer)-1 DO hd[i] := buffer[i]; END;
  1217. device(Usb.UsbDevice).controller.SetHubDescriptor(hd);
  1218. RETURN TRUE;
  1219. END SetHubDescriptor;
  1220. (* Clear a root hub feature. *)
  1221. PROCEDURE ClearHubFeature(feature : LONGINT) : BOOLEAN;
  1222. BEGIN
  1223. IF Debug.StrongChecks THEN ASSERT((feature = HubLocalPowerChange) OR (feature = HubOverCurrentChange)); END; (* Valid feature selector *)
  1224. (* TODO: Do nothing? *)
  1225. RETURN TRUE;
  1226. END ClearHubFeature;
  1227. (* Set a root hub feature *)
  1228. PROCEDURE SetHubFeature(feature : LONGINT) : BOOLEAN;
  1229. BEGIN
  1230. IF Debug.StrongChecks THEN ASSERT((feature = HubLocalPowerChange) OR (feature = HubOverCurrentChange)); END; (* Valid feature selector *)
  1231. (* TODO: Do nothing? *)
  1232. RETURN TRUE;
  1233. END SetHubFeature;
  1234. (* Clear a root hub port feature. *)
  1235. PROCEDURE ClearPortFeature(feature, port, selector : LONGINT) : BOOLEAN;
  1236. VAR res : BOOLEAN;
  1237. BEGIN
  1238. IF Debug.StrongChecks THEN
  1239. ASSERT((port >= 0) & (port < nbrOfPorts));
  1240. ASSERT(((feature # PortTest) & (feature # PortIndicator)) OR (selector = 0));
  1241. ASSERT((feature > 0) & (feature <= 22) & (feature # PortConnection)); (* Valid feature selector *)
  1242. END;
  1243. IF Debug.Trace & Debug.traceHubRequests THEN Show("Port "); KernelLog.Int(port + 1, 0); KernelLog.String(": Clear feature "); KernelLog.Int(feature, 0); KernelLog.Ln; END;
  1244. CASE feature OF
  1245. PortEnable : hub.controller.DisablePort(port); res := TRUE;
  1246. | PortSuspend : res := hub.controller.ResumePort(port);
  1247. | PortPower: hub.controller.DisablePortPower(port); res := TRUE;
  1248. | PortIndicator: hub.controller.IndicatePort(port, selector); res := TRUE;
  1249. | PortConnectionChange:
  1250. | PortResetChange:
  1251. | PortEnableChange:
  1252. | PortSuspendChange:
  1253. | PortOverCurrentChange:
  1254. ELSE
  1255. IF Debug.Level >= Debug.Warnings THEN Show("Clearing of Feature "); KernelLog.Int(feature, 0); KernelLog.String(" not supported"); KernelLog.Ln; END;
  1256. END;
  1257. RETURN res;
  1258. END ClearPortFeature;
  1259. (* Set a root hub port feature *)
  1260. PROCEDURE SetPortFeature(feature, port, selector : LONGINT) : BOOLEAN;
  1261. VAR res : BOOLEAN;
  1262. BEGIN
  1263. IF Debug.StrongChecks THEN
  1264. ASSERT((port >= 0) & (port < nbrOfPorts));
  1265. ASSERT(((feature = PortTest) OR (feature = PortIndicator)) OR (selector = 0));
  1266. ASSERT((feature > 0) & (feature <= 22) & (feature # PortConnection)); (* Valid feature selector *)
  1267. END;
  1268. IF Debug.Trace & Debug.traceHubRequests THEN Show("Port "); KernelLog.Int(port + 1, 0); KernelLog.String(": Set feature "); KernelLog.Int(feature, 0); KernelLog.Ln; END;
  1269. CASE feature OF
  1270. PortEnable : res := hub.controller.ResetAndEnablePort(port);
  1271. | PortSuspend : res := hub.controller.SuspendPort(port);
  1272. | PortPower: hub.controller.EnablePortPower(port); res := TRUE;
  1273. | PortReset: res := hub.controller.ResetAndEnablePort(port);
  1274. | PortTest:
  1275. | PortIndicator: hub.controller.IndicatePort(port, selector); res := TRUE;
  1276. | PortConnectionChange:
  1277. | PortResetChange:
  1278. | PortEnableChange:
  1279. | PortSuspendChange:
  1280. | PortOverCurrentChange:
  1281. ELSE
  1282. IF Debug.Level >= Debug.Warnings THEN Show("Request not supported"); KernelLog.Ln; END;
  1283. END;
  1284. RETURN res;
  1285. END SetPortFeature;
  1286. (* Return the root hubs status. Reported: Local power supply good & Overcurrent *)
  1287. PROCEDURE GetHubStatus(VAR hubstatus : SET) : BOOLEAN;
  1288. BEGIN
  1289. (* HsLocalPowerLost and HsLocalPowerSourceChange are never set since root hubs cannot not loose power *)
  1290. hubstatus := {};
  1291. (* TODO: report global overcurrent here *)
  1292. RETURN TRUE;
  1293. END GetHubStatus;
  1294. (* Get the status of the specifed root hub port. Note that the HCD is responsible for acknowledging changes. *)
  1295. PROCEDURE GetPortStatus(port : LONGINT; ack : BOOLEAN) : SET;
  1296. BEGIN
  1297. IF Debug.StrongChecks THEN ASSERT((port >= 0) & (port < nbrOfPorts)); END;
  1298. RETURN hub.controller.GetPortStatus(port, ack);
  1299. END GetPortStatus;
  1300. (* Root hubs that support interrupt notification for port status changes will call this
  1301. handler when a corresponding interrupt occurs. The parameters are ignored. *)
  1302. PROCEDURE HandleStatusChange(status : Usbdi.Status; actLen : LONGINT);
  1303. BEGIN {EXCLUSIVE}
  1304. statusChange := TRUE;
  1305. END HandleStatusChange;
  1306. (* How much current (mA) is available for this hub? *)
  1307. PROCEDURE AvailableCurrent() : LONGINT;
  1308. BEGIN
  1309. RETURN 500; (* High power port delivers 500mA *)
  1310. END AvailableCurrent;
  1311. (* Active object control *)
  1312. PROCEDURE Terminate; BEGIN {EXCLUSIVE} alive:=FALSE; timerRH.Wakeup; END Terminate;
  1313. PROCEDURE SetDead; BEGIN {EXCLUSIVE} dead := TRUE; END SetDead;
  1314. PROCEDURE AwaitDead; BEGIN {EXCLUSIVE} AWAIT(dead); END AwaitDead;
  1315. (* Root hub specific initialization *)
  1316. PROCEDURE Initialize() : BOOLEAN;
  1317. BEGIN
  1318. IF hub.controller.SetStatusChangeHandler(HandleStatusChange) THEN
  1319. (* Root hub driver will be wake up via interrupt notification *)
  1320. pollingInterval := 0;
  1321. END;
  1322. BEGIN {EXCLUSIVE} initialized := TRUE; END;
  1323. RETURN TRUE;
  1324. END Initialize;
  1325. (* Displays message containing a description of this hub and the specified text to kernel log *)
  1326. PROCEDURE Show(CONST text : ARRAY OF CHAR);
  1327. BEGIN
  1328. KernelLog.String("UsbHubDriver: Root Hub "); hub.ShowName; KernelLog.String(": "); KernelLog.String(text);
  1329. END Show;
  1330. PROCEDURE Disconnect;
  1331. BEGIN
  1332. Terminate; AwaitDead;
  1333. IF Debug.Verbose THEN Show("Disconnected."); KernelLog.Ln; END;
  1334. END Disconnect;
  1335. PROCEDURE &New*;
  1336. BEGIN
  1337. New^; NEW(timerRH);
  1338. alive := TRUE; dead := FALSE; initialized := FALSE;
  1339. pollingInterval := PollingInterval;
  1340. END New;
  1341. BEGIN {ACTIVE}
  1342. (* Root hubs use a different way to communicate root hub port status changes. Either, they cannot *)
  1343. (* report there changes at all and must be polled (e.g. UHCI host controllers), or they use interrupt driven *)
  1344. (* global status change notification (e.g. OHCI and EHCI host controllers). *)
  1345. BEGIN {EXCLUSIVE} AWAIT(initialized OR ~alive); END;
  1346. WHILE alive DO
  1347. (* The first time we poll the bus (force bus enumeration) *)
  1348. LookForDevices;
  1349. IF pollingInterval = 0 THEN (* Use interrupt handler port status change notification *)
  1350. BEGIN {EXCLUSIVE}
  1351. AWAIT((alive = FALSE) OR (statusChange = TRUE));
  1352. statusChange := FALSE;
  1353. END;
  1354. ELSE (* Use polling *)
  1355. timerRH.Sleep(pollingInterval);
  1356. END;
  1357. END;
  1358. SetDead;
  1359. END RootHubDriver;
  1360. VAR
  1361. (* This is a linked list of all running root hub drivers. It's only used by the module termination handler. *)
  1362. rootHubs : RootHubDriver;
  1363. (* This is the Probe procedure of the internal USB hub driver / root hub driver. *)
  1364. PROCEDURE Probe(dev : Usbdi.UsbDevice; id : Usbdi.InterfaceDescriptor) : Usbdi.Driver;
  1365. VAR hubDriver : UsbHubDriver; rootHubDriver : RootHubDriver;
  1366. BEGIN
  1367. IF dev.descriptor.bNumConfigurations # 1 THEN RETURN NIL; END;
  1368. IF dev.configurations[0].bNumInterfaces # 1 THEN RETURN NIL; END;
  1369. IF id.bInterfaceClass # 9 THEN RETURN NIL; END;
  1370. IF id.bInterfaceSubClass # 0 THEN RETURN NIL; END;
  1371. IF id.bNumEndpoints # 1 THEN RETURN NIL; END;
  1372. IF dev(Usb.UsbDevice).parent = dev THEN (* It's a root hub *)
  1373. NEW(rootHubDriver);
  1374. (* Insert at head of root hub driver linked list *)
  1375. rootHubDriver.next := rootHubs; rootHubs := rootHubDriver;
  1376. RETURN rootHubDriver;
  1377. ELSE (* It's a hub device attached to the bus *)
  1378. NEW(hubDriver);
  1379. RETURN hubDriver;
  1380. END;
  1381. END Probe;
  1382. PROCEDURE Cleanup;
  1383. VAR rh : RootHubDriver;
  1384. BEGIN
  1385. rh := rootHubs;
  1386. WHILE(rh # NIL) DO
  1387. IF Debug.Verbose THEN rh.Show("Shutting down... "); KernelLog.Ln; END;
  1388. rh.Terminate; rh.AwaitDead;
  1389. rh := rh.next;
  1390. END;
  1391. Usbdi.drivers.Remove(Name);
  1392. IF Debug.Verbose THEN KernelLog.Enter; KernelLog.String("UsbHubDriver: Removed hub driver."); KernelLog.Exit; END;
  1393. END Cleanup;
  1394. (** Install the USB Hub Driver *)
  1395. PROCEDURE Install*;
  1396. END Install;
  1397. BEGIN
  1398. Modules.InstallTermHandler(Cleanup);
  1399. Usbdi.drivers.Add(Probe, Name, Description, 10);
  1400. END UsbHubDriver.
  1401. UsbHubDriver.Install ~ SystemTools.Free UsbHubDriver ~