USB Host Shield 2.0
Loading...
Searching...
No Matches
cdcftdi.cpp
Go to the documentation of this file.
1/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
2
3This software may be distributed and modified under the terms of the GNU
4General Public License version 2 (GPL2) as published by the Free Software
5Foundation and appearing in the file GPL2.TXT included in the packaging of
6this file. Please note that GPL2 Section 2[b] requires that all works based
7on this software must also be made publicly available under the terms of
8the GPL2 ("Copyleft").
9
10Contact information
11-------------------
12
13Circuits At Home, LTD
14Web : http://www.circuitsathome.com
15e-mail : support@circuitsathome.com
16 */
17#include "cdcftdi.h"
18
19const uint8_t FTDI::epDataInIndex = 1;
20const uint8_t FTDI::epDataOutIndex = 2;
21const uint8_t FTDI::epInterruptInIndex = 3;
22
24pAsync(pasync),
25pUsb(p),
26bAddress(0),
27bNumEP(1),
28wFTDIType(0),
29wIdProduct(idProduct) {
30 for(uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) {
31 epInfo[i].epAddr = 0;
32 epInfo[i].maxPktSize = (i) ? 0 : 8;
33 epInfo[i].bmSndToggle = 0;
34 epInfo[i].bmRcvToggle = 0;
35 epInfo[i].bmNakPower = (i == epDataInIndex) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
36 }
37 if(pUsb)
38 pUsb->RegisterDeviceClass(this);
39}
40
43
45 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
47 UsbDevice *p = NULL;
49
50 uint8_t num_of_conf; // number of configurations
51
52 AddressPool &addrPool = pUsb->GetAddressPool();
53
54 USBTRACE("FTDI Init\r\n");
55
56 if(bAddress) {
57 USBTRACE("FTDI CLASS IN USE??\r\n");
59 }
60 // Get pointer to pseudo device with address 0 assigned
61 p = addrPool.GetUsbDevicePtr(0);
62
63 if(!p) {
64 USBTRACE("FTDI NO ADDRESS??\r\n");
66 }
67 if(!p->epinfo) {
68 USBTRACE("epinfo\r\n");
70 }
71
72 // Save old pointer to EP_RECORD of address 0
73 oldep_ptr = p->epinfo;
74
75 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
76 p->epinfo = epInfo;
77
78 p->lowspeed = lowspeed;
79
80 // Get device descriptor
81 rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), buf);
82
83 // Restore p->epinfo
84 p->epinfo = oldep_ptr;
85
86 if(rcode) {
87 goto FailGetDevDescr;
88 }
89 if(udd->idVendor != FTDI_VID || udd->idProduct != wIdProduct) {
90 USBTRACE("FTDI Init: Product not supported\r\n");
91 USBTRACE2("Expected VID:", FTDI_VID);
92 USBTRACE2("Found VID:", udd->idVendor);
93
94 USBTRACE2("Expected PID:", wIdProduct);
95 USBTRACE2("Found PID:", udd->idProduct);
97 }
98
99 // Save type of FTDI chip
100 wFTDIType = udd->bcdDevice;
101
102 // Allocate new address according to device class
103 bAddress = addrPool.AllocAddress(parent, false, port);
104
105 if(!bAddress)
107
108 // Extract Max Packet Size from the device descriptor
109 epInfo[0].maxPktSize = udd->bMaxPacketSize0;
110 // Some devices set endpoint lengths to zero, which is incorrect.
111 // we should check them, and if zero, set them to 64.
112 if(epInfo[0].maxPktSize == 0) epInfo[0].maxPktSize = 64;
113
114 // Assign new address to the device
115 rcode = pUsb->setAddr(0, 0, bAddress);
116
117 if(rcode) {
118 p->lowspeed = false;
119 addrPool.FreeAddress(bAddress);
120 bAddress = 0;
121 USBTRACE2("setAddr:", rcode);
122 return rcode;
123 }
124
125 USBTRACE2("Addr:", bAddress);
126
127 p->lowspeed = false;
128
129 p = addrPool.GetUsbDevicePtr(bAddress);
130
131 if(!p)
133
134 p->lowspeed = lowspeed;
135
136 num_of_conf = udd->bNumConfigurations;
137
138 // Assign epInfo to epinfo pointer
139 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
140
141 if(rcode)
143
144 USBTRACE2("NC:", num_of_conf);
145
146 for(uint8_t i = 0; i < num_of_conf; i++) {
148
149 // This interferes with serial output, and should be opt-in for debugging.
150 //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
151 //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
152 //if(rcode)
153 // goto FailGetConfDescr;
154
155 rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
156
157 if(rcode)
158 goto FailGetConfDescr;
159
160 if(bNumEP > 1)
161 break;
162 } // for
163
164 if(bNumEP < 2)
166
167 USBTRACE2("NumEP:", bNumEP);
168
169 // Assign epInfo to epinfo pointer
170 rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
171
172 USBTRACE2("Conf:", bConfNum);
173
174 // Set Configuration Value
175 rcode = pUsb->setConf(bAddress, 0, bConfNum);
176
177 if(rcode)
178 goto FailSetConfDescr;
179
180 // default latency is 16ms on-chip, reduce it to 1
181 rcode = SetLatency(1);
182 if(rcode)
183 goto FailOnLatency;
184
185
186 rcode = pAsync->OnInit(this);
187
188 if(rcode)
189 goto FailOnInit;
190
191 USBTRACE("FTDI configured\r\n");
192
193 ready = true;
194 return 0;
195
197#ifdef DEBUG_USB_HOST
198 USBTRACE("SetLatency: ");
199 goto Fail;
200#endif
201
203#ifdef DEBUG_USB_HOST
205 goto Fail;
206#endif
207
209#ifdef DEBUG_USB_HOST
211 goto Fail;
212#endif
213
215#ifdef DEBUG_USB_HOST
217 goto Fail;
218#endif
219
221#ifdef DEBUG_USB_HOST
223 goto Fail;
224#endif
225
227#ifdef DEBUG_USB_HOST
228 USBTRACE("OnInit:");
229
230Fail:
232#endif
233 Release();
234 return rcode;
235}
236
238 ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
239 ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
240 ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
241
242 bConfNum = conf;
243
244 uint8_t index;
245
246 if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80)
247 index = epInterruptInIndex;
248 else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK)
249 index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
250 else
251 return;
252
253 // Fill in the endpoint info structure
254 epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
255 epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
256 epInfo[index].bmSndToggle = 0;
257 epInfo[index].bmRcvToggle = 0;
258 // Some device vendors set endpoint lengths to zero, which is incorrect.
259 // Check, and if zero, set to 64.
260 if(epInfo[index].maxPktSize == 0) epInfo[index].maxPktSize = 64;
261
262 bNumEP++;
263
264 PrintEndpointDescriptor(pep);
265}
266
268 pUsb->GetAddressPool().FreeAddress(bAddress);
269
270 bAddress = 0;
271 bNumEP = 1;
272 qNextPollTime = 0;
273 bPollEnable = false;
274 ready = false;
275 return pAsync->OnRelease(this);
276}
277
279 uint8_t rcode = 0;
280
281 //if (!bPollEnable)
282 // return 0;
283
284 //if (qNextPollTime <= (uint32_t)millis())
285 //{
286 // USB_HOST_SERIAL.println(bAddress, HEX);
287
288 // qNextPollTime = (uint32_t)millis() + 100;
289 //}
290 return rcode;
291}
292
296 divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left
297
298 if(wFTDIType == FT232AM) {
299 if((divisor3 & 0x7) == 7)
300 divisor3++; // round x.7/8 up to x+1
301
302 baud_value = divisor3 >> 3;
303 divisor3 &= 0x7;
304
305 if(divisor3 == 1) baud_value |= 0xc000;
306 else // 0.125
307 if(divisor3 >= 4) baud_value |= 0x4000;
308 else // 0.5
309 if(divisor3 != 0) baud_value |= 0x8000; // 0.25
310 if(baud_value == 1) baud_value = 0; /* special case for maximum baud rate */
311 } else {
312 static const uint8_t divfrac [8] = {0, 3, 2, 0, 1, 1, 2, 3};
313 static const uint8_t divindex[8] = {0, 0, 0, 1, 0, 1, 1, 1};
314
315 baud_value = divisor3 >> 3;
316 baud_value |= divfrac [divisor3 & 0x7] << 14;
318
319 /* Deal with special cases for highest baud rates. */
320 if(baud_value == 1) baud_value = 0;
321 else // 1.0
322 if(baud_value == 0x4001) baud_value = 1; // 1.5
323 }
324 USBTRACE2("baud_value:", baud_value);
325 USBTRACE2("baud_index:", baud_index);
326 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_BAUD_RATE, baud_value & 0xff, baud_value >> 8, baud_index, 0, 0, NULL, NULL);
327 if(rv && rv != hrNAK) {
328 Release();
329 }
330 return rv;
331}
332
333// No docs on if this is 8 or 16 bit, so play it safe, make maximum 255ms
334
336 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_LATENCY_TIMER, l, 0, 0, 0, 0, NULL, NULL);
337 if(rv && rv != hrNAK) {
338 Release();
339 }
340 return rv;
341}
342
343// No docs on if this is 8 or 16 bit, so play it safe, make maximum 255ms
344
346 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_GET_LATENCY_TIMER, 0, 0, 0, 0, 1, (uint8_t *)l, NULL);
347 if(rv && rv != hrNAK) {
348 Release();
349 }
350 return rv;
351}
352
354 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_MODEM_CTRL, signal & 0xff, signal >> 8, 0, 0, 0, NULL, NULL);
355 if(rv && rv != hrNAK) {
356 Release();
357 }
358 return rv;
359}
360
362 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_FLOW_CTRL, xon, xoff, protocol << 8, 0, 0, NULL, NULL);
363 if(rv && rv != hrNAK) {
364 Release();
365 }
366 return rv;
367}
368
370 uint8_t rv = pUsb->ctrlReq(bAddress, 0, bmREQ_FTDI_OUT, FTDI_SIO_SET_DATA, databm & 0xff, databm >> 8, 0, 0, 0, NULL, NULL);
371 if(rv && rv != hrNAK) {
372 Release();
373 }
374 return rv;
375}
376
378 uint8_t rv = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr);
379 if(rv && rv != hrNAK) {
380 Release();
381 }
382 return rv;
383}
384
386 uint8_t rv = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr);
387 if(rv && rv != hrNAK) {
388 Release();
389 }
390 return rv;
391}
392
393void FTDI::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
394 Notify(PSTR("Endpoint descriptor:"), 0x80);
395 Notify(PSTR("\r\nLength:\t\t"), 0x80);
396 D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
397 Notify(PSTR("\r\nType:\t\t"), 0x80);
398 D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
399 Notify(PSTR("\r\nAddress:\t"), 0x80);
400 D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
401 Notify(PSTR("\r\nAttributes:\t"), 0x80);
402 D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
403 Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
404 D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
405 Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
406 D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
407 Notify(PSTR("\r\n"), 0x80);
408}
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition UsbCore.h:103
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition UsbCore.h:108
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
Definition UsbCore.h:100
#define USB_ERROR_EPINFO_IS_NULL
Definition UsbCore.h:106
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition UsbCore.h:105
#define USB_NAK_MAX_POWER
Definition address.h:34
#define USB_NAK_NOWAIT
Definition address.h:36
#define FTDI_SIO_MODEM_CTRL
Definition cdcftdi.h:38
#define FT232AM
Definition cdcftdi.h:31
#define FTDI_SIO_GET_LATENCY_TIMER
Definition cdcftdi.h:46
#define FTDI_VID
Definition cdcftdi.h:28
#define bmREQ_FTDI_OUT
Definition cdcftdi.h:22
#define FTDI_MAX_ENDPOINTS
Definition cdcftdi.h:96
#define FTDI_SIO_SET_FLOW_CTRL
Definition cdcftdi.h:39
#define FTDI_SIO_SET_LATENCY_TIMER
Definition cdcftdi.h:45
#define FTDI_SIO_SET_DATA
Definition cdcftdi.h:41
#define FTDI_SIO_SET_BAUD_RATE
Definition cdcftdi.h:40
virtual void FreeAddress(uint8_t addr)=0
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
virtual uint8_t OnInit(FTDI *pftdi)
Definition cdcftdi.h:84
virtual uint8_t OnRelease(FTDI *pftdi)
Definition cdcftdi.h:88
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition cdcftdi.cpp:41
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition cdcftdi.cpp:237
uint8_t Poll()
Definition cdcftdi.cpp:278
uint8_t GetLatency(uint8_t *l)
Definition cdcftdi.cpp:345
uint8_t SetFlowControl(uint8_t protocol, uint8_t xon=0x11, uint8_t xoff=0x13)
Definition cdcftdi.cpp:361
uint8_t SetModemControl(uint16_t control)
Definition cdcftdi.cpp:353
uint8_t SndData(uint16_t nbytes, uint8_t *dataptr)
Definition cdcftdi.cpp:385
uint8_t SetLatency(uint8_t l)
Definition cdcftdi.cpp:335
uint8_t RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr)
Definition cdcftdi.cpp:377
uint8_t Release()
Definition cdcftdi.cpp:267
uint8_t SetData(uint16_t databm)
Definition cdcftdi.cpp:369
uint8_t SetBaudRate(uint32_t baud)
Definition cdcftdi.cpp:293
FTDI(USB *pusb, FTDIAsyncOper *pasync, uint16_t idProduct=FTDI_PID)
Definition cdcftdi.cpp:23
Definition UsbCore.h:220
AddressPool & GetAddressPool()
Definition UsbCore.h:236
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition Usb.cpp:801
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition Usb.cpp:850
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition Usb.cpp:841
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition UsbCore.h:240
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition Usb.cpp:806
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t *dataptr, USBReadParser *p)
Definition Usb.cpp:126
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition Usb.cpp:64
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval=0)
Definition Usb.cpp:209
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *data)
Definition Usb.cpp:303
#define USBTRACE2(s, r)
Definition macros.h:84
#define USBTRACE(s)
Definition macros.h:82
#define hrNAK
Definition max3421e.h:218
#define NotifyFailSetConfDescr(...)
Definition message.h:60
#define NotifyFail(...)
Definition message.h:62
#define Notify(...)
Definition message.h:51
#define NotifyFailGetConfDescr(...)
Definition message.h:56
#define NotifyFailSetDevTblEntry(...)
Definition message.h:55
#define NotifyFailGetDevDescr(...)
Definition message.h:54
uint8_t bmNakPower
Definition address.h:49
uint8_t bmRcvToggle
Definition address.h:48
uint8_t epAddr
Definition address.h:40
uint8_t maxPktSize
Definition address.h:41
uint8_t bmSndToggle
Definition address.h:47
#define USB_TRANSFER_TYPE_BULK
Definition usb_ch9.h:92
#define bmUSB_TRANSFER_TYPE
Definition usb_ch9.h:94
#define USB_TRANSFER_TYPE_INTERRUPT
Definition usb_ch9.h:93
#define PSTR(str)