1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
14 Web : http://www.circuitsathome.com
15 e-mail : support@circuitsathome.com
19 const uint8_t FTDI::epDataInIndex
= 1;
20 const uint8_t FTDI::epDataOutIndex
= 2;
21 const uint8_t FTDI::epInterruptInIndex
= 3;
23 FTDI::FTDI(USB
*p
, FTDIAsyncOper
*pasync
) :
29 for(uint8_t i
= 0; i
< FTDI_MAX_ENDPOINTS
; i
++) {
31 epInfo
[i
].maxPktSize
= (i
) ? 0 : 8;
32 epInfo
[i
].epAttribs
= 0;
33 epInfo
[i
].bmNakPower
= (i
==epDataInIndex
) ? USB_NAK_NOWAIT
: USB_NAK_MAX_POWER
;
36 pUsb
->RegisterDeviceClass(this);
39 uint8_t FTDI::Init(uint8_t parent
, uint8_t port
, bool lowspeed
) {
40 const uint8_t constBufSize
= sizeof (USB_DEVICE_DESCRIPTOR
);
42 uint8_t buf
[constBufSize
];
43 USB_DEVICE_DESCRIPTOR
* udd
= reinterpret_cast<USB_DEVICE_DESCRIPTOR
*>(buf
);
46 EpInfo
*oldep_ptr
= NULL
;
48 uint8_t num_of_conf
; // number of configurations
50 AddressPool
&addrPool
= pUsb
->GetAddressPool();
52 USBTRACE("FTDI Init\r\n");
55 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
;
57 // Get pointer to pseudo device with address 0 assigned
58 p
= addrPool
.GetUsbDevicePtr(0);
61 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
;
64 USBTRACE("epinfo\r\n");
65 return USB_ERROR_EPINFO_IS_NULL
;
68 // Save old pointer to EP_RECORD of address 0
69 oldep_ptr
= p
->epinfo
;
71 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
74 p
->lowspeed
= lowspeed
;
76 // Get device descriptor
77 rcode
= pUsb
->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR
), buf
);
80 p
->epinfo
= oldep_ptr
;
84 if(udd
->idVendor
!= FTDI_VID
|| udd
->idProduct
!= FTDI_PID
)
85 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
;
87 // Save type of FTDI chip
88 wFTDIType
= udd
->bcdDevice
;
90 // Allocate new address according to device class
91 bAddress
= addrPool
.AllocAddress(parent
, false, port
);
94 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
;
96 // Extract Max Packet Size from the device descriptor
97 epInfo
[0].maxPktSize
= udd
->bMaxPacketSize0
;
99 // Assign new address to the device
100 rcode
= pUsb
->setAddr(0, 0, bAddress
);
104 addrPool
.FreeAddress(bAddress
);
106 USBTRACE2("setAddr:", rcode
);
110 USBTRACE2("Addr:", bAddress
);
114 p
= addrPool
.GetUsbDevicePtr(bAddress
);
117 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
;
119 p
->lowspeed
= lowspeed
;
121 num_of_conf
= udd
->bNumConfigurations
;
123 // Assign epInfo to epinfo pointer
124 rcode
= pUsb
->setEpInfoEntry(bAddress
, 1, epInfo
);
127 goto FailSetDevTblEntry
;
129 USBTRACE2("NC:", num_of_conf
);
131 for(uint8_t i
= 0; i
< num_of_conf
; i
++) {
132 HexDumper
<USBReadParser
, uint16_t, uint16_t> HexDump
;
133 ConfigDescParser
< 0xFF, 0xFF, 0xFF, CP_MASK_COMPARE_ALL
> confDescrParser(this);
135 rcode
= pUsb
->getConfDescr(bAddress
, 0, i
, &HexDump
);
138 goto FailGetConfDescr
;
140 rcode
= pUsb
->getConfDescr(bAddress
, 0, i
, &confDescrParser
);
143 goto FailGetConfDescr
;
150 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
;
152 USBTRACE2("NumEP:", bNumEP
);
154 // Assign epInfo to epinfo pointer
155 rcode
= pUsb
->setEpInfoEntry(bAddress
, bNumEP
, epInfo
);
157 USBTRACE2("Conf:", bConfNum
);
159 // Set Configuration Value
160 rcode
= pUsb
->setConf(bAddress
, 0, bConfNum
);
163 goto FailSetConfDescr
;
165 rcode
= pAsync
->OnInit(this);
170 USBTRACE("FTDI configured\r\n");
176 #ifdef DEBUG_USB_HOST
177 NotifyFailGetDevDescr();
182 #ifdef DEBUG_USB_HOST
183 NotifyFailSetDevTblEntry();
188 #ifdef DEBUG_USB_HOST
189 NotifyFailGetConfDescr();
194 #ifdef DEBUG_USB_HOST
195 NotifyFailSetConfDescr();
200 #ifdef DEBUG_USB_HOST
210 void FTDI::EndpointXtract(uint8_t conf
, uint8_t iface
, uint8_t alt
, uint8_t proto
, const USB_ENDPOINT_DESCRIPTOR
*pep
) {
211 ErrorMessage
<uint8_t > (PSTR("Conf.Val"), conf
);
212 ErrorMessage
<uint8_t > (PSTR("Iface Num"), iface
);
213 ErrorMessage
<uint8_t > (PSTR("Alt.Set"), alt
);
219 if((pep
->bmAttributes
& 0x03) == 3 && (pep
->bEndpointAddress
& 0x80) == 0x80)
220 index
= epInterruptInIndex
;
222 if((pep
->bmAttributes
& 0x02) == 2)
223 index
= ((pep
->bEndpointAddress
& 0x80) == 0x80) ? epDataInIndex
: epDataOutIndex
;
227 // Fill in the endpoint info structure
228 epInfo
[index
].epAddr
= (pep
->bEndpointAddress
& 0x0F);
229 epInfo
[index
].maxPktSize
= (uint8_t)pep
->wMaxPacketSize
;
230 epInfo
[index
].epAttribs
= 0;
234 PrintEndpointDescriptor(pep
);
237 uint8_t FTDI::Release() {
238 pUsb
->GetAddressPool().FreeAddress(bAddress
);
244 return pAsync
->OnRelease(this);
247 uint8_t FTDI::Poll() {
253 //if (qNextPollTime <= millis())
255 // USB_HOST_SERIAL.println(bAddress, HEX);
257 // qNextPollTime = millis() + 100;
262 uint8_t FTDI::SetBaudRate(uint32_t baud
) {
263 uint16_t baud_value
, baud_index
= 0;
266 divisor3
= 48000000 / 2 / baud
; // divisor shifted 3 bits to the left
268 if(wFTDIType
== FT232AM
) {
269 if((divisor3
& 0x7) == 7)
270 divisor3
++; // round x.7/8 up to x+1
272 baud_value
= divisor3
>> 3;
275 if(divisor3
== 1) baud_value
|= 0xc000;
277 if(divisor3
>= 4) baud_value
|= 0x4000;
279 if(divisor3
!= 0) baud_value
|= 0x8000; // 0.25
280 if(baud_value
== 1) baud_value
= 0; /* special case for maximum baud rate */
282 static const unsigned char divfrac
[8] = {0, 3, 2, 0, 1, 1, 2, 3};
283 static const unsigned char divindex
[8] = {0, 0, 0, 1, 0, 1, 1, 1};
285 baud_value
= divisor3
>> 3;
286 baud_value
|= divfrac
[divisor3
& 0x7] << 14;
287 baud_index
= divindex
[divisor3
& 0x7];
289 /* Deal with special cases for highest baud rates. */
290 if(baud_value
== 1) baud_value
= 0;
292 if(baud_value
== 0x4001) baud_value
= 1; // 1.5
294 USBTRACE2("baud_value:", baud_value
);
295 USBTRACE2("baud_index:", baud_index
);
296 return pUsb
->ctrlReq(bAddress
, 0, bmREQ_FTDI_OUT
, FTDI_SIO_SET_BAUD_RATE
, baud_value
& 0xff, baud_value
>> 8, baud_index
, 0, 0, NULL
, NULL
);
299 uint8_t FTDI::SetModemControl(uint16_t signal
) {
300 return pUsb
->ctrlReq(bAddress
, 0, bmREQ_FTDI_OUT
, FTDI_SIO_MODEM_CTRL
, signal
& 0xff, signal
>> 8, 0, 0, 0, NULL
, NULL
);
303 uint8_t FTDI::SetFlowControl(uint8_t protocol
, uint8_t xon
, uint8_t xoff
) {
304 return pUsb
->ctrlReq(bAddress
, 0, bmREQ_FTDI_OUT
, FTDI_SIO_SET_FLOW_CTRL
, xon
, xoff
, protocol
<< 8, 0, 0, NULL
, NULL
);
307 uint8_t FTDI::SetData(uint16_t databm
) {
308 return pUsb
->ctrlReq(bAddress
, 0, bmREQ_FTDI_OUT
, FTDI_SIO_SET_DATA
, databm
& 0xff, databm
>> 8, 0, 0, 0, NULL
, NULL
);
311 uint8_t FTDI::RcvData(uint16_t *bytes_rcvd
, uint8_t *dataptr
) {
312 return pUsb
->inTransfer(bAddress
, epInfo
[epDataInIndex
].epAddr
, bytes_rcvd
, dataptr
);
315 uint8_t FTDI::SndData(uint16_t nbytes
, uint8_t *dataptr
) {
316 return pUsb
->outTransfer(bAddress
, epInfo
[epDataOutIndex
].epAddr
, nbytes
, dataptr
);
319 void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR
* ep_ptr
) {
320 Notify(PSTR("Endpoint descriptor:"), 0x80);
321 Notify(PSTR("\r\nLength:\t\t"), 0x80);
322 D_PrintHex
<uint8_t > (ep_ptr
->bLength
, 0x80);
323 Notify(PSTR("\r\nType:\t\t"), 0x80);
324 D_PrintHex
<uint8_t > (ep_ptr
->bDescriptorType
, 0x80);
325 Notify(PSTR("\r\nAddress:\t"), 0x80);
326 D_PrintHex
<uint8_t > (ep_ptr
->bEndpointAddress
, 0x80);
327 Notify(PSTR("\r\nAttributes:\t"), 0x80);
328 D_PrintHex
<uint8_t > (ep_ptr
->bmAttributes
, 0x80);
329 Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
330 D_PrintHex
<uint16_t > (ep_ptr
->wMaxPacketSize
, 0x80);
331 Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
332 D_PrintHex
<uint8_t > (ep_ptr
->bInterval
, 0x80);
333 Notify(PSTR("\r\n"), 0x80);