ftdi.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. ftdi.c
  5. Abstract:
  6. This module implements the FTDI USB to Serial Port KD USB driver.
  7. Author:
  8. Evan Green 3-Apr-2014
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include "kdusbp.h"
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. #define KD_FTDI_CONFIGURATION_BUFFER_SIZE 256
  21. #define FTDI_REQUEST_RESET 0x00
  22. #define FTDI_REQUEST_SET_BAUD_RATE 0x03
  23. #define FTDI_INTERFACE_ANY 0
  24. #define FTDI_INTERFACE_A 1
  25. #define FTDI_INTERFACE_B 2
  26. #define FTDI_INTERFACE_C 3
  27. #define FTDI_INTERFACE_D 4
  28. #define FTDI_REVISION_AM 0x200
  29. #define FTDI_REVISION_BM 0x400
  30. #define FTDI_REVISION_2232C 0x500
  31. #define FTDI_FUNDAMENTAL_CLOCK 24000000
  32. #define FTDI_MAX_DIVISOR_AM 0x1FFF8
  33. #define FTDI_MAX_DIVISOR_BM 0x1FFFF
  34. //
  35. // Define the number of status bytes that come in before every read.
  36. //
  37. #define FTDI_READ_STATUS_SIZE 2
  38. //
  39. // ------------------------------------------------------ Data Type Definitions
  40. //
  41. typedef enum _FTDI_CHIP_TYPE {
  42. FtdiTypeInvalid,
  43. FtdiTypeOld,
  44. FtdiTypeAm,
  45. FtdiTypeBm,
  46. FtdiType2232C
  47. } FTDI_CHIP_TYPE, *PFTDI_CHIP_TYPE;
  48. /*++
  49. Structure Description:
  50. This structure describes the context of an FTDI USB device.
  51. Members:
  52. Device - Stores a pointer to the USB device.
  53. BulkOutEndpoint - Stores the bulk out endpoint information.
  54. BulkInEndpoint - Stores the bulk in endpoint information.
  55. TransferOut - Stores the outgoing transfer.
  56. TransferIn - Stores the incoming transfer.
  57. TransferInOffset - Stores the current offset to the IN transfer data where
  58. the next byte to be returned is.
  59. TransferInQueued - Stores a boolean indicating whether or not the
  60. receive transfer has been submitted.
  61. TransferInSetup - Stores a boolean indicating whether or not the receive
  62. transfer has been set up (and therefore needs retiring).
  63. Index - Stores the serial port to talk to. See FTDI_INTERFACE_* definitions.
  64. ChipType - Stores the chip type.
  65. --*/
  66. typedef struct _KD_FTDI_DEVICE {
  67. PKD_USB_DEVICE Device;
  68. DEBUG_USB_ENDPOINT BulkOutEndpoint;
  69. DEBUG_USB_ENDPOINT BulkInEndpoint;
  70. DEBUG_USB_TRANSFER TransferOut;
  71. DEBUG_USB_TRANSFER TransferIn;
  72. ULONG TransferInOffset;
  73. BOOL TransferInQueued;
  74. BOOL TransferInSetup;
  75. USHORT Index;
  76. FTDI_CHIP_TYPE ChipType;
  77. } KD_FTDI_DEVICE, *PKD_FTDI_DEVICE;
  78. //
  79. // ----------------------------------------------- Internal Function Prototypes
  80. //
  81. KSTATUS
  82. KdpFtdiReset (
  83. PVOID Context,
  84. ULONG BaudRate
  85. );
  86. KSTATUS
  87. KdpFtdiTransmit (
  88. PVOID Context,
  89. PVOID Data,
  90. ULONG Size
  91. );
  92. KSTATUS
  93. KdpFtdiReceive (
  94. PVOID Context,
  95. PVOID Data,
  96. PULONG Size
  97. );
  98. KSTATUS
  99. KdpFtdiGetStatus (
  100. PVOID Context,
  101. PBOOL ReceiveDataAvailable
  102. );
  103. VOID
  104. KdpFtdiDisconnect (
  105. PVOID Context
  106. );
  107. KSTATUS
  108. KdpFtdiInitializeEndpoints (
  109. PKD_FTDI_DEVICE Device
  110. );
  111. ULONG
  112. KdpFtdiCalculateDivisor (
  113. PKD_FTDI_DEVICE Device,
  114. ULONG BaudRate,
  115. PUSHORT Value,
  116. PUSHORT Index
  117. );
  118. //
  119. // -------------------------------------------------------------------- Globals
  120. //
  121. CHAR KdFtdiAmAdjustUp[8] = {0, 0, 0, 1, 0, 3, 2, 1};
  122. CHAR KdFtdiAmAdjustDown[8] = {0, 0, 0, 1, 0, 1, 2, 3};
  123. CHAR KdFtdiFractionCode[8] = {0, 3, 2, 4, 1, 5, 6, 7};
  124. DEBUG_DEVICE_DESCRIPTION KdFtdiInterfaceTemplate = {
  125. DEBUG_DEVICE_DESCRIPTION_VERSION,
  126. {
  127. KdpFtdiReset,
  128. KdpFtdiTransmit,
  129. KdpFtdiReceive,
  130. KdpFtdiGetStatus,
  131. KdpFtdiDisconnect
  132. },
  133. NULL
  134. };
  135. //
  136. // Store the single device instance.
  137. //
  138. KD_FTDI_DEVICE KdFtdiDevice;
  139. //
  140. // ------------------------------------------------------------------ Functions
  141. //
  142. KSTATUS
  143. KdpFtdiDriverEntry (
  144. PKD_USB_DEVICE Device,
  145. PDEBUG_DEVICE_DESCRIPTION Interface
  146. )
  147. /*++
  148. Routine Description:
  149. This routine initializes an FTDI USB to Serial KD USB device.
  150. Arguments:
  151. Device - Supplies a pointer to the device the driver lives on.
  152. Interface - Supplies a pointer where the driver fills in the I/O
  153. interface on success.
  154. Return Value:
  155. Status code.
  156. --*/
  157. {
  158. PKD_FTDI_DEVICE FtdiDevice;
  159. KSTATUS Status;
  160. //
  161. // Use a single static device.
  162. //
  163. FtdiDevice = &KdFtdiDevice;
  164. RtlZeroMemory(FtdiDevice, sizeof(KD_FTDI_DEVICE));
  165. FtdiDevice->Device = Device;
  166. Status = KdpFtdiInitializeEndpoints(FtdiDevice);
  167. if (!KSUCCESS(Status)) {
  168. goto FtdiDriverEntry;
  169. }
  170. RtlCopyMemory(Interface,
  171. &KdFtdiInterfaceTemplate,
  172. sizeof(DEBUG_DEVICE_DESCRIPTION));
  173. Interface->Context = FtdiDevice;
  174. FtdiDriverEntry:
  175. return Status;
  176. }
  177. //
  178. // --------------------------------------------------------- Internal Functions
  179. //
  180. KSTATUS
  181. KdpFtdiReset (
  182. PVOID Context,
  183. ULONG BaudRate
  184. )
  185. /*++
  186. Routine Description:
  187. This routine initializes and resets a debug device, preparing it to send
  188. and receive data.
  189. Arguments:
  190. Context - Supplies the pointer to the port's context, provided by the
  191. hardware module upon initialization.
  192. BaudRate - Supplies the baud rate to set.
  193. Return Value:
  194. STATUS_SUCCESS on success.
  195. Other status codes on failure. The device will not be used if a failure
  196. status code is returned.
  197. --*/
  198. {
  199. PKD_FTDI_DEVICE Device;
  200. ULONG Length;
  201. USB_SETUP_PACKET Setup;
  202. KSTATUS Status;
  203. Device = Context;
  204. if ((Device->TransferInQueued != FALSE) ||
  205. (Device->TransferInSetup != FALSE)) {
  206. Status = KdpUsbRetireTransfer(Device->Device->Controller,
  207. &(Device->TransferIn));
  208. if (!KSUCCESS(Status)) {
  209. goto FtdiResetEnd;
  210. }
  211. Device->TransferInQueued = FALSE;
  212. Device->TransferInSetup = FALSE;
  213. }
  214. //
  215. // Always skip the two status bytes at the beginning of each read.
  216. //
  217. Device->TransferInOffset = FTDI_READ_STATUS_SIZE;
  218. //
  219. // Reset the device.
  220. //
  221. Setup.RequestType = USB_SETUP_REQUEST_TO_DEVICE |
  222. USB_SETUP_REQUEST_VENDOR |
  223. USB_SETUP_REQUEST_DEVICE_RECIPIENT;
  224. Setup.Request = FTDI_REQUEST_RESET;
  225. Setup.Value = 0;
  226. Setup.Index = Device->Index;
  227. Setup.Length = 0;
  228. Length = Setup.Length;
  229. Status = KdpUsbDefaultControlTransfer(Device->Device,
  230. &Setup,
  231. DebugUsbTransferDirectionOut,
  232. NULL,
  233. &Length);
  234. if (!KSUCCESS(Status)) {
  235. goto FtdiResetEnd;
  236. }
  237. //
  238. // Set the baud rate.
  239. //
  240. Setup.Request = FTDI_REQUEST_SET_BAUD_RATE;
  241. KdpFtdiCalculateDivisor(Device, BaudRate, &(Setup.Value), &(Setup.Index));
  242. Status = KdpUsbDefaultControlTransfer(Device->Device,
  243. &Setup,
  244. DebugUsbTransferDirectionOut,
  245. NULL,
  246. &Length);
  247. if (!KSUCCESS(Status)) {
  248. goto FtdiResetEnd;
  249. }
  250. //
  251. // Initialize the outbound and inbound transfers.
  252. //
  253. RtlZeroMemory(&(Device->TransferOut), sizeof(DEBUG_USB_TRANSFER));
  254. Device->TransferOut.Endpoint = &(Device->BulkOutEndpoint);
  255. Device->TransferOut.Direction = DebugUsbTransferDirectionOut;
  256. Device->TransferOut.Length = 0;
  257. RtlZeroMemory(&(Device->TransferIn), sizeof(DEBUG_USB_TRANSFER));
  258. Device->TransferIn.Endpoint = &(Device->BulkInEndpoint);
  259. Device->TransferIn.Direction = DebugUsbTransferDirectionIn;
  260. Device->TransferIn.Length = 0;
  261. //
  262. // Reset the endpoints.
  263. //
  264. Device->BulkInEndpoint.DataToggle = FALSE;
  265. Device->BulkOutEndpoint.DataToggle = FALSE;
  266. FtdiResetEnd:
  267. return Status;
  268. }
  269. KSTATUS
  270. KdpFtdiTransmit (
  271. PVOID Context,
  272. PVOID Data,
  273. ULONG Size
  274. )
  275. /*++
  276. Routine Description:
  277. This routine transmits data from the host out through the debug device.
  278. Arguments:
  279. Context - Supplies the pointer to the port's context, provided by the
  280. hardware module upon initialization.
  281. Data - Supplies a pointer to the data to write.
  282. Size - Supplies the size to write, in bytes.
  283. Return Value:
  284. STATUS_SUCCESS on success.
  285. STATUS_DEVICE_IO_ERROR if a device error occurred.
  286. --*/
  287. {
  288. ULONG BytesThisRound;
  289. PKD_FTDI_DEVICE Device;
  290. KSTATUS Status;
  291. Device = Context;
  292. while (Size != 0) {
  293. BytesThisRound = Device->BulkOutEndpoint.MaxPacketSize;
  294. if (BytesThisRound > Size) {
  295. BytesThisRound = Size;
  296. }
  297. Device->TransferOut.Length = BytesThisRound;
  298. Status = KdpUsbSetupTransfer(Device->Device->Controller,
  299. &(Device->TransferOut));
  300. if (!KSUCCESS(Status)) {
  301. goto FtdiTransmitEnd;
  302. }
  303. RtlCopyMemory(Device->TransferOut.Buffer, Data, BytesThisRound);
  304. Status = KdpUsbSubmitTransfer(Device->Device->Controller,
  305. &(Device->TransferOut),
  306. TRUE);
  307. KdpUsbRetireTransfer(Device->Device->Controller,
  308. &(Device->TransferOut));
  309. if (!KSUCCESS(Status)) {
  310. goto FtdiTransmitEnd;
  311. }
  312. Data += BytesThisRound;
  313. Size -= BytesThisRound;
  314. }
  315. Status = STATUS_SUCCESS;
  316. FtdiTransmitEnd:
  317. return Status;
  318. }
  319. KSTATUS
  320. KdpFtdiReceive (
  321. PVOID Context,
  322. PVOID Data,
  323. PULONG Size
  324. )
  325. /*++
  326. Routine Description:
  327. This routine receives incoming data from the debug device.
  328. Arguments:
  329. Context - Supplies the pointer to the port's context, provided by the
  330. hardware module upon initialization.
  331. Data - Supplies a pointer where the read data will be returned on success.
  332. Size - Supplies a pointer that on input contains the size of the receive
  333. buffer. On output, returns the number of bytes read.
  334. Return Value:
  335. STATUS_SUCCESS on success.
  336. STATUS_NO_DATA_AVAILABLE if there was no data to be read at the current
  337. time.
  338. STATUS_DEVICE_IO_ERROR if a device error occurred.
  339. --*/
  340. {
  341. ULONG BytesThisRound;
  342. ULONG BytesToRead;
  343. PHARDWARE_USB_DEBUG_DEVICE Controller;
  344. PKD_FTDI_DEVICE Device;
  345. KSTATUS Status;
  346. PDEBUG_USB_TRANSFER TransferIn;
  347. Device = Context;
  348. Controller = Device->Device->Controller;
  349. TransferIn = &(Device->TransferIn);
  350. BytesToRead = *Size;
  351. Status = STATUS_SUCCESS;
  352. while (BytesToRead != 0) {
  353. //
  354. // If the transfer is currently queued, check to see if it's finished.
  355. //
  356. if (Device->TransferInQueued != FALSE) {
  357. Status = KdpUsbCheckTransfer(Controller, TransferIn);
  358. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  359. if (BytesToRead != *Size) {
  360. Status = STATUS_SUCCESS;
  361. } else {
  362. Status = STATUS_NO_DATA_AVAILABLE;
  363. }
  364. break;
  365. //
  366. // If checking the transfer failed, retire it and stop.
  367. //
  368. } else if (!KSUCCESS(Status)) {
  369. KdpUsbRetireTransfer(Controller, TransferIn);
  370. Device->TransferIn.LengthTransferred = 0;
  371. Device->TransferInQueued = FALSE;
  372. Device->TransferInSetup = FALSE;
  373. break;
  374. }
  375. //
  376. // The transfer is complete. Set the offset to skip the two status
  377. // bytes.
  378. //
  379. Device->TransferInQueued = FALSE;
  380. Device->TransferInOffset = FTDI_READ_STATUS_SIZE;
  381. }
  382. //
  383. // Copy bytes from the completed transfer.
  384. //
  385. if (Device->TransferInOffset < TransferIn->LengthTransferred) {
  386. BytesThisRound = TransferIn->LengthTransferred -
  387. Device->TransferInOffset;
  388. if (BytesThisRound > BytesToRead) {
  389. BytesThisRound = BytesToRead;
  390. }
  391. RtlCopyMemory(Data,
  392. TransferIn->Buffer + Device->TransferInOffset,
  393. BytesThisRound);
  394. Device->TransferInOffset += BytesThisRound;
  395. BytesToRead -= BytesThisRound;
  396. Data += BytesThisRound;
  397. }
  398. //
  399. // If the transfer was completely consumed by the caller, resubmit the
  400. // transfer.
  401. //
  402. if (Device->TransferInOffset >= TransferIn->LengthTransferred) {
  403. //
  404. // Retire the transfer if it hasn't been done yet.
  405. //
  406. if (Device->TransferInSetup != FALSE) {
  407. KdpUsbRetireTransfer(Controller, TransferIn);
  408. Device->TransferInSetup = FALSE;
  409. }
  410. //
  411. // Set up the transfer.
  412. //
  413. Device->TransferIn.Length = Device->BulkInEndpoint.MaxPacketSize;
  414. Status = KdpUsbSetupTransfer(Controller, TransferIn);
  415. if (!KSUCCESS(Status)) {
  416. break;
  417. }
  418. Device->TransferInSetup = TRUE;
  419. //
  420. // Submit the transfer asynchronously.
  421. //
  422. Status = KdpUsbSubmitTransfer(Controller, TransferIn, FALSE);
  423. if (!KSUCCESS(Status)) {
  424. KdpUsbRetireTransfer(Controller, TransferIn);
  425. Device->TransferInSetup = FALSE;
  426. break;
  427. }
  428. Device->TransferInQueued = TRUE;
  429. }
  430. }
  431. //
  432. // Return the number of bytes transferred.
  433. //
  434. *Size = *Size - BytesToRead;
  435. return Status;
  436. }
  437. KSTATUS
  438. KdpFtdiGetStatus (
  439. PVOID Context,
  440. PBOOL ReceiveDataAvailable
  441. )
  442. /*++
  443. Routine Description:
  444. This routine returns the current device status.
  445. Arguments:
  446. Context - Supplies the pointer to the port's context, provided by the
  447. hardware module upon initialization.
  448. ReceiveDataAvailable - Supplies a pointer where a boolean will be returned
  449. indicating whether or not receive data is available.
  450. Return Value:
  451. Status code.
  452. --*/
  453. {
  454. PHARDWARE_USB_DEBUG_DEVICE Controller;
  455. PKD_FTDI_DEVICE Device;
  456. KSTATUS Status;
  457. PDEBUG_USB_TRANSFER TransferIn;
  458. *ReceiveDataAvailable = FALSE;
  459. Device = Context;
  460. Controller = Device->Device->Controller;
  461. TransferIn = &(Device->TransferIn);
  462. //
  463. // If there is still data to read from a previous transfer, return that
  464. // there is data available.
  465. //
  466. if ((Device->TransferInSetup != FALSE) &&
  467. (Device->TransferInQueued == FALSE)) {
  468. if (Device->TransferInOffset < TransferIn->LengthTransferred) {
  469. *ReceiveDataAvailable = TRUE;
  470. Status = STATUS_SUCCESS;
  471. goto FtdiGetStatusEnd;
  472. //
  473. // This situation shouldn't hit, as it implies that the receive loop
  474. // ran out of data but didn't retire the transfer. Handle it anyway.
  475. //
  476. } else {
  477. KdpUsbRetireTransfer(Controller, TransferIn);
  478. Device->TransferInSetup = FALSE;
  479. }
  480. }
  481. //
  482. // Set up the transfer if it is not yet created.
  483. //
  484. if (Device->TransferInSetup == FALSE) {
  485. Device->TransferIn.Length = Device->BulkInEndpoint.MaxPacketSize;
  486. Status = KdpUsbSetupTransfer(Controller, TransferIn);
  487. if (!KSUCCESS(Status)) {
  488. goto FtdiGetStatusEnd;
  489. }
  490. Device->TransferInSetup = TRUE;
  491. }
  492. //
  493. // Submit the transfer (asynchronously) if it is not already queued.
  494. //
  495. if (Device->TransferInQueued == FALSE) {
  496. Status = KdpUsbSubmitTransfer(Controller, TransferIn, FALSE);
  497. if (!KSUCCESS(Status)) {
  498. KdpUsbRetireTransfer(Controller, TransferIn);
  499. Device->TransferInSetup = FALSE;
  500. goto FtdiGetStatusEnd;
  501. }
  502. Device->TransferInQueued = TRUE;
  503. }
  504. //
  505. // Check the transfer to see if it's finished.
  506. //
  507. Status = KdpUsbCheckTransfer(Controller, TransferIn);
  508. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  509. Status = STATUS_SUCCESS;
  510. } else if ((!KSUCCESS(Status)) ||
  511. (TransferIn->LengthTransferred <= FTDI_READ_STATUS_SIZE)) {
  512. KdpUsbRetireTransfer(Controller, TransferIn);
  513. Device->TransferInQueued = FALSE;
  514. Device->TransferInSetup = FALSE;
  515. //
  516. // If there was data other than the status bytes, return it.
  517. //
  518. } else {
  519. Device->TransferInQueued = FALSE;
  520. Device->TransferInOffset = FTDI_READ_STATUS_SIZE;
  521. *ReceiveDataAvailable = TRUE;
  522. }
  523. FtdiGetStatusEnd:
  524. return Status;
  525. }
  526. VOID
  527. KdpFtdiDisconnect (
  528. PVOID Context
  529. )
  530. /*++
  531. Routine Description:
  532. This routine disconnects a device, taking it offline.
  533. Arguments:
  534. Context - Supplies the pointer to the port's context, provided by the
  535. hardware module upon initialization.
  536. Return Value:
  537. None.
  538. --*/
  539. {
  540. PKD_FTDI_DEVICE Device;
  541. Device = Context;
  542. //
  543. // Cancel the IN transfer.
  544. //
  545. if (Device->TransferInSetup != FALSE) {
  546. KdpUsbRetireTransfer(Device->Device->Controller, &(Device->TransferIn));
  547. Device->TransferInQueued = FALSE;
  548. Device->TransferInSetup = FALSE;
  549. }
  550. return;
  551. }
  552. KSTATUS
  553. KdpFtdiInitializeEndpoints (
  554. PKD_FTDI_DEVICE Device
  555. )
  556. /*++
  557. Routine Description:
  558. This routine reads the configuration descriptor and initializes the FTDI
  559. endpoint information.
  560. Arguments:
  561. Device - Supplies a pointer to the FTDI device.
  562. Return Value:
  563. Status code.
  564. --*/
  565. {
  566. UCHAR Buffer[KD_FTDI_CONFIGURATION_BUFFER_SIZE];
  567. PUSB_CONFIGURATION_DESCRIPTOR Configuration;
  568. PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;
  569. PUSB_ENDPOINT_DESCRIPTOR Endpoint;
  570. ULONG EndpointCount;
  571. ULONG EndpointIndex;
  572. BOOL FoundIn;
  573. BOOL FoundOut;
  574. PUSB_INTERFACE_DESCRIPTOR Interface;
  575. ULONG Length;
  576. USB_SETUP_PACKET Setup;
  577. KSTATUS Status;
  578. Device->ChipType = FtdiTypeBm;
  579. //
  580. // Request the default configuration.
  581. //
  582. RtlZeroMemory(&Setup, sizeof(USB_SETUP_PACKET));
  583. Setup.RequestType = USB_SETUP_REQUEST_TO_HOST |
  584. USB_SETUP_REQUEST_STANDARD |
  585. USB_SETUP_REQUEST_DEVICE_RECIPIENT;
  586. Setup.Request = USB_DEVICE_REQUEST_GET_DESCRIPTOR;
  587. Setup.Value = (UsbDescriptorTypeConfiguration << 8) | 0;
  588. Setup.Index = 0;
  589. Setup.Length = sizeof(Buffer);
  590. Length = Setup.Length;
  591. Configuration = (PUSB_CONFIGURATION_DESCRIPTOR)Buffer;
  592. Status = KdpUsbDefaultControlTransfer(Device->Device,
  593. &Setup,
  594. DebugUsbTransferDirectionIn,
  595. Configuration,
  596. &Length);
  597. if (!KSUCCESS(Status)) {
  598. goto FtdiInitializeEndpointsEnd;
  599. }
  600. if (Length < sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
  601. Status = STATUS_INVALID_CONFIGURATION;
  602. goto FtdiInitializeEndpointsEnd;
  603. }
  604. //
  605. // Loop through the interfaces looking for a hub interface.
  606. //
  607. FoundIn = FALSE;
  608. FoundOut = FALSE;
  609. Interface = (PUSB_INTERFACE_DESCRIPTOR)((PVOID)Configuration +
  610. Configuration->Length);
  611. if (Configuration->InterfaceCount == 2) {
  612. Device->ChipType = FtdiType2232C;
  613. if (Device->Index == FTDI_INTERFACE_ANY) {
  614. Device->Index = FTDI_INTERFACE_A;
  615. }
  616. }
  617. while ((UINTN)(Interface + 1) <= (UINTN)Buffer + Length) {
  618. Endpoint = ((PVOID)Interface) + Interface->Length;
  619. if (Interface->DescriptorType == UsbDescriptorTypeInterface) {
  620. FoundIn = FALSE;
  621. FoundOut = FALSE;
  622. //
  623. // Loop through all the endpoints in the interface.
  624. //
  625. EndpointIndex = 0;
  626. EndpointCount = Interface->EndpointCount;
  627. while (((UINTN)(Endpoint + 1) <= ((UINTN)Buffer + Length)) &&
  628. (EndpointIndex < EndpointCount)) {
  629. if (Endpoint->DescriptorType == UsbDescriptorTypeEndpoint) {
  630. if ((Endpoint->Attributes &
  631. USB_ENDPOINT_ATTRIBUTES_TYPE_MASK) ==
  632. USB_ENDPOINT_ATTRIBUTES_TYPE_BULK) {
  633. if ((Endpoint->EndpointAddress &
  634. USB_ENDPOINT_ADDRESS_DIRECTION_IN) != 0) {
  635. Status = KdpUsbInitializeEndpoint(
  636. Device->Device,
  637. Endpoint,
  638. &(Device->BulkInEndpoint));
  639. if (KSUCCESS(Status)) {
  640. FoundIn = TRUE;
  641. }
  642. } else {
  643. Status = KdpUsbInitializeEndpoint(
  644. Device->Device,
  645. Endpoint,
  646. &(Device->BulkOutEndpoint));
  647. if (KSUCCESS(Status)) {
  648. FoundOut = TRUE;
  649. }
  650. }
  651. }
  652. EndpointIndex += 1;
  653. }
  654. Endpoint = ((PVOID)Endpoint) + Endpoint->Length;
  655. }
  656. if ((FoundIn != FALSE) && (FoundOut != FALSE)) {
  657. break;
  658. }
  659. }
  660. Interface = (PVOID)Endpoint;
  661. }
  662. if ((FoundIn == FALSE) || (FoundOut == FALSE)) {
  663. Status = STATUS_INVALID_CONFIGURATION;
  664. goto FtdiInitializeEndpointsEnd;
  665. }
  666. //
  667. // Request the device descriptor to get the version out of it.
  668. //
  669. Setup.RequestType = USB_SETUP_REQUEST_TO_HOST |
  670. USB_SETUP_REQUEST_STANDARD |
  671. USB_SETUP_REQUEST_DEVICE_RECIPIENT;
  672. Setup.Request = USB_DEVICE_REQUEST_GET_DESCRIPTOR;
  673. Setup.Value = UsbDescriptorTypeDevice << 8;
  674. Setup.Index = 0;
  675. Setup.Length = sizeof(USB_DEVICE_DESCRIPTOR);
  676. Length = Setup.Length;
  677. DeviceDescriptor = (PUSB_DEVICE_DESCRIPTOR)Buffer;
  678. Status = KdpUsbDefaultControlTransfer(Device->Device,
  679. &Setup,
  680. DebugUsbTransferDirectionIn,
  681. DeviceDescriptor,
  682. &Length);
  683. if (!KSUCCESS(Status)) {
  684. goto FtdiInitializeEndpointsEnd;
  685. }
  686. if (Length != Setup.Length) {
  687. Status = STATUS_DATA_LENGTH_MISMATCH;
  688. goto FtdiInitializeEndpointsEnd;
  689. }
  690. if (DeviceDescriptor->DescriptorType != UsbDescriptorTypeDevice) {
  691. Status = STATUS_DEVICE_IO_ERROR;
  692. goto FtdiInitializeEndpointsEnd;
  693. }
  694. if (DeviceDescriptor->DeviceRevision < FTDI_REVISION_AM) {
  695. Device->ChipType = FtdiTypeOld;
  696. } else if ((DeviceDescriptor->DeviceRevision < FTDI_REVISION_BM) &&
  697. (DeviceDescriptor->SerialNumberStringIndex != 0)) {
  698. Device->ChipType = FtdiTypeAm;
  699. } else if (DeviceDescriptor->DeviceRevision < FTDI_REVISION_2232C) {
  700. Device->ChipType = FtdiTypeBm;
  701. }
  702. Status = STATUS_SUCCESS;
  703. FtdiInitializeEndpointsEnd:
  704. return Status;
  705. }
  706. ULONG
  707. KdpFtdiCalculateDivisor (
  708. PKD_FTDI_DEVICE Device,
  709. ULONG BaudRate,
  710. PUSHORT Value,
  711. PUSHORT Index
  712. )
  713. /*++
  714. Routine Description:
  715. This routine computes the divisor (in the form of index and value fields of
  716. a setup packet) for a given baud rate.
  717. Arguments:
  718. Device - Supplies a pointer to the FTDI device.
  719. BaudRate - Supplies the desired baud rate.
  720. Value - Supplies a pointer where the value field will be returned on
  721. success.
  722. Index - Supplies a pointer where th index field will be returned on success.
  723. Return Value:
  724. Returns the actual baud rate.
  725. --*/
  726. {
  727. ULONG BaudRateDifference;
  728. ULONG BaudRateEstimate;
  729. ULONG BestBaudRate;
  730. ULONG BestBaudRateDifference;
  731. ULONG BestDivisor;
  732. ULONG Divisor;
  733. ULONG EncodedDivisor;
  734. ULONG Try;
  735. ULONG TryDivisor;
  736. if (BaudRate == 0) {
  737. return 0;
  738. }
  739. Divisor = FTDI_FUNDAMENTAL_CLOCK / BaudRate;
  740. //
  741. // On AM devices, round down to one of the supported fractional values.
  742. //
  743. if (Device->ChipType == FtdiTypeAm) {
  744. Divisor -= KdFtdiAmAdjustDown[Divisor & 0x7];
  745. }
  746. //
  747. // Try this divisor and the one above it to see which one is closer.
  748. //
  749. BestBaudRate = 0;
  750. BestBaudRateDifference = -1;
  751. BestDivisor = Divisor;
  752. for (Try = 0; Try < 2; Try += 1) {
  753. TryDivisor = Divisor + Try;
  754. //
  755. // Round up to the minimum divisor value. BM doesn't support 9
  756. // through 11, AM doesn't support 9 through 15.
  757. //
  758. if (TryDivisor <= 8) {
  759. TryDivisor = 8;
  760. } else if ((Device->ChipType > FtdiTypeAm) && (TryDivisor < 12)) {
  761. TryDivisor = 12;
  762. } else if (Divisor < 16) {
  763. TryDivisor = 16;
  764. } else {
  765. //
  766. // For AM devices, round up to the nearest supported fraction. Also
  767. // make sure the divisor doesn't exceed the maximum.
  768. //
  769. if (Device->ChipType <= FtdiTypeAm) {
  770. TryDivisor = KdFtdiAmAdjustUp[TryDivisor & 7];
  771. if (TryDivisor > FTDI_MAX_DIVISOR_AM) {
  772. TryDivisor = FTDI_MAX_DIVISOR_AM;
  773. }
  774. } else {
  775. if (TryDivisor > FTDI_MAX_DIVISOR_BM) {
  776. TryDivisor = FTDI_MAX_DIVISOR_BM;
  777. }
  778. }
  779. }
  780. //
  781. // Go back from the divisor to the baud rate to see how bad the error
  782. // is.
  783. //
  784. BaudRateEstimate = (FTDI_FUNDAMENTAL_CLOCK + (TryDivisor / 2)) /
  785. TryDivisor;
  786. if (BaudRateEstimate < BaudRate) {
  787. BaudRateDifference = BaudRate - BaudRateEstimate;
  788. } else {
  789. BaudRateDifference = BaudRateEstimate - BaudRate;
  790. }
  791. if ((Try == 0) || (BaudRateDifference < BestBaudRateDifference)) {
  792. BestDivisor = TryDivisor;
  793. BestBaudRate = BaudRateEstimate;
  794. BestBaudRateDifference = BaudRateDifference;
  795. if (BaudRateDifference == 0) {
  796. break;
  797. }
  798. }
  799. }
  800. //
  801. // Encode the winning divisor.
  802. //
  803. EncodedDivisor = (BestDivisor >> 3) |
  804. (KdFtdiFractionCode[BestDivisor & 0x7] << 14);
  805. //
  806. // Handle some special cases outlined in the FTDI spec. An encoded divisor
  807. // of 0 is 3000000 baud, and 1 is 2000000 baud.
  808. //
  809. if (EncodedDivisor == 1) {
  810. EncodedDivisor = 0;
  811. } else if (EncodedDivisor == 0x4001) {
  812. EncodedDivisor = 1;
  813. }
  814. //
  815. // Split the encoded divisor into index and value fields.
  816. //
  817. *Value = (USHORT)(EncodedDivisor & 0xFFFF);
  818. if (Device->ChipType == FtdiType2232C) {
  819. *Index = ((USHORT)(EncodedDivisor >> 8) & 0xFF00) | Device->Index;
  820. } else {
  821. *Index = (USHORT)(EncodedDivisor >> 16);
  822. }
  823. return BestBaudRate;
  824. }