diff options
Diffstat (limited to 'lib/usbhost/USB_Host_Shield_2.0/cdcftdi.cpp')
-rw-r--r-- | lib/usbhost/USB_Host_Shield_2.0/cdcftdi.cpp | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/lib/usbhost/USB_Host_Shield_2.0/cdcftdi.cpp b/lib/usbhost/USB_Host_Shield_2.0/cdcftdi.cpp new file mode 100644 index 000000000..80d21d16e --- /dev/null +++ b/lib/usbhost/USB_Host_Shield_2.0/cdcftdi.cpp | |||
@@ -0,0 +1,334 @@ | |||
1 | /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. | ||
2 | |||
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 | ||
8 | the GPL2 ("Copyleft"). | ||
9 | |||
10 | Contact information | ||
11 | ------------------- | ||
12 | |||
13 | Circuits At Home, LTD | ||
14 | Web : http://www.circuitsathome.com | ||
15 | e-mail : support@circuitsathome.com | ||
16 | */ | ||
17 | #include "cdcftdi.h" | ||
18 | |||
19 | const uint8_t FTDI::epDataInIndex = 1; | ||
20 | const uint8_t FTDI::epDataOutIndex = 2; | ||
21 | const uint8_t FTDI::epInterruptInIndex = 3; | ||
22 | |||
23 | FTDI::FTDI(USB *p, FTDIAsyncOper *pasync) : | ||
24 | pAsync(pasync), | ||
25 | pUsb(p), | ||
26 | bAddress(0), | ||
27 | bNumEP(1), | ||
28 | wFTDIType(0) { | ||
29 | for(uint8_t i = 0; i < FTDI_MAX_ENDPOINTS; i++) { | ||
30 | epInfo[i].epAddr = 0; | ||
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; | ||
34 | } | ||
35 | if(pUsb) | ||
36 | pUsb->RegisterDeviceClass(this); | ||
37 | } | ||
38 | |||
39 | uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) { | ||
40 | const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); | ||
41 | |||
42 | uint8_t buf[constBufSize]; | ||
43 | USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); | ||
44 | uint8_t rcode; | ||
45 | UsbDevice *p = NULL; | ||
46 | EpInfo *oldep_ptr = NULL; | ||
47 | |||
48 | uint8_t num_of_conf; // number of configurations | ||
49 | |||
50 | AddressPool &addrPool = pUsb->GetAddressPool(); | ||
51 | |||
52 | USBTRACE("FTDI Init\r\n"); | ||
53 | |||
54 | if(bAddress) | ||
55 | return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; | ||
56 | |||
57 | // Get pointer to pseudo device with address 0 assigned | ||
58 | p = addrPool.GetUsbDevicePtr(0); | ||
59 | |||
60 | if(!p) | ||
61 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
62 | |||
63 | if(!p->epinfo) { | ||
64 | USBTRACE("epinfo\r\n"); | ||
65 | return USB_ERROR_EPINFO_IS_NULL; | ||
66 | } | ||
67 | |||
68 | // Save old pointer to EP_RECORD of address 0 | ||
69 | oldep_ptr = p->epinfo; | ||
70 | |||
71 | // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence | ||
72 | p->epinfo = epInfo; | ||
73 | |||
74 | p->lowspeed = lowspeed; | ||
75 | |||
76 | // Get device descriptor | ||
77 | rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), buf); | ||
78 | |||
79 | // Restore p->epinfo | ||
80 | p->epinfo = oldep_ptr; | ||
81 | |||
82 | if(rcode) | ||
83 | goto FailGetDevDescr; | ||
84 | if(udd->idVendor != FTDI_VID || udd->idProduct != FTDI_PID) | ||
85 | return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; | ||
86 | |||
87 | // Save type of FTDI chip | ||
88 | wFTDIType = udd->bcdDevice; | ||
89 | |||
90 | // Allocate new address according to device class | ||
91 | bAddress = addrPool.AllocAddress(parent, false, port); | ||
92 | |||
93 | if(!bAddress) | ||
94 | return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; | ||
95 | |||
96 | // Extract Max Packet Size from the device descriptor | ||
97 | epInfo[0].maxPktSize = udd->bMaxPacketSize0; | ||
98 | |||
99 | // Assign new address to the device | ||
100 | rcode = pUsb->setAddr(0, 0, bAddress); | ||
101 | |||
102 | if(rcode) { | ||
103 | p->lowspeed = false; | ||
104 | addrPool.FreeAddress(bAddress); | ||
105 | bAddress = 0; | ||
106 | USBTRACE2("setAddr:", rcode); | ||
107 | return rcode; | ||
108 | } | ||
109 | |||
110 | USBTRACE2("Addr:", bAddress); | ||
111 | |||
112 | p->lowspeed = false; | ||
113 | |||
114 | p = addrPool.GetUsbDevicePtr(bAddress); | ||
115 | |||
116 | if(!p) | ||
117 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
118 | |||
119 | p->lowspeed = lowspeed; | ||
120 | |||
121 | num_of_conf = udd->bNumConfigurations; | ||
122 | |||
123 | // Assign epInfo to epinfo pointer | ||
124 | rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); | ||
125 | |||
126 | if(rcode) | ||
127 | goto FailSetDevTblEntry; | ||
128 | |||
129 | USBTRACE2("NC:", num_of_conf); | ||
130 | |||
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); | ||
134 | |||
135 | rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); | ||
136 | |||
137 | if(rcode) | ||
138 | goto FailGetConfDescr; | ||
139 | |||
140 | rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); | ||
141 | |||
142 | if(rcode) | ||
143 | goto FailGetConfDescr; | ||
144 | |||
145 | if(bNumEP > 1) | ||
146 | break; | ||
147 | } // for | ||
148 | |||
149 | if(bNumEP < 2) | ||
150 | return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; | ||
151 | |||
152 | USBTRACE2("NumEP:", bNumEP); | ||
153 | |||
154 | // Assign epInfo to epinfo pointer | ||
155 | rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); | ||
156 | |||
157 | USBTRACE2("Conf:", bConfNum); | ||
158 | |||
159 | // Set Configuration Value | ||
160 | rcode = pUsb->setConf(bAddress, 0, bConfNum); | ||
161 | |||
162 | if(rcode) | ||
163 | goto FailSetConfDescr; | ||
164 | |||
165 | rcode = pAsync->OnInit(this); | ||
166 | |||
167 | if(rcode) | ||
168 | goto FailOnInit; | ||
169 | |||
170 | USBTRACE("FTDI configured\r\n"); | ||
171 | |||
172 | bPollEnable = true; | ||
173 | return 0; | ||
174 | |||
175 | FailGetDevDescr: | ||
176 | #ifdef DEBUG_USB_HOST | ||
177 | NotifyFailGetDevDescr(); | ||
178 | goto Fail; | ||
179 | #endif | ||
180 | |||
181 | FailSetDevTblEntry: | ||
182 | #ifdef DEBUG_USB_HOST | ||
183 | NotifyFailSetDevTblEntry(); | ||
184 | goto Fail; | ||
185 | #endif | ||
186 | |||
187 | FailGetConfDescr: | ||
188 | #ifdef DEBUG_USB_HOST | ||
189 | NotifyFailGetConfDescr(); | ||
190 | goto Fail; | ||
191 | #endif | ||
192 | |||
193 | FailSetConfDescr: | ||
194 | #ifdef DEBUG_USB_HOST | ||
195 | NotifyFailSetConfDescr(); | ||
196 | goto Fail; | ||
197 | #endif | ||
198 | |||
199 | FailOnInit: | ||
200 | #ifdef DEBUG_USB_HOST | ||
201 | USBTRACE("OnInit:"); | ||
202 | |||
203 | Fail: | ||
204 | NotifyFail(rcode); | ||
205 | #endif | ||
206 | Release(); | ||
207 | return rcode; | ||
208 | } | ||
209 | |||
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); | ||
214 | |||
215 | bConfNum = conf; | ||
216 | |||
217 | uint8_t index; | ||
218 | |||
219 | if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) | ||
220 | index = epInterruptInIndex; | ||
221 | else | ||
222 | if((pep->bmAttributes & 0x02) == 2) | ||
223 | index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; | ||
224 | else | ||
225 | return; | ||
226 | |||
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; | ||
231 | |||
232 | bNumEP++; | ||
233 | |||
234 | PrintEndpointDescriptor(pep); | ||
235 | } | ||
236 | |||
237 | uint8_t FTDI::Release() { | ||
238 | pUsb->GetAddressPool().FreeAddress(bAddress); | ||
239 | |||
240 | bAddress = 0; | ||
241 | bNumEP = 1; | ||
242 | qNextPollTime = 0; | ||
243 | bPollEnable = false; | ||
244 | return pAsync->OnRelease(this); | ||
245 | } | ||
246 | |||
247 | uint8_t FTDI::Poll() { | ||
248 | uint8_t rcode = 0; | ||
249 | |||
250 | //if (!bPollEnable) | ||
251 | // return 0; | ||
252 | |||
253 | //if (qNextPollTime <= millis()) | ||
254 | //{ | ||
255 | // USB_HOST_SERIAL.println(bAddress, HEX); | ||
256 | |||
257 | // qNextPollTime = millis() + 100; | ||
258 | //} | ||
259 | return rcode; | ||
260 | } | ||
261 | |||
262 | uint8_t FTDI::SetBaudRate(uint32_t baud) { | ||
263 | uint16_t baud_value, baud_index = 0; | ||
264 | uint32_t divisor3; | ||
265 | |||
266 | divisor3 = 48000000 / 2 / baud; // divisor shifted 3 bits to the left | ||
267 | |||
268 | if(wFTDIType == FT232AM) { | ||
269 | if((divisor3 & 0x7) == 7) | ||
270 | divisor3++; // round x.7/8 up to x+1 | ||
271 | |||
272 | baud_value = divisor3 >> 3; | ||
273 | divisor3 &= 0x7; | ||
274 | |||
275 | if(divisor3 == 1) baud_value |= 0xc000; | ||
276 | else // 0.125 | ||
277 | if(divisor3 >= 4) baud_value |= 0x4000; | ||
278 | else // 0.5 | ||
279 | if(divisor3 != 0) baud_value |= 0x8000; // 0.25 | ||
280 | if(baud_value == 1) baud_value = 0; /* special case for maximum baud rate */ | ||
281 | } else { | ||
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}; | ||
284 | |||
285 | baud_value = divisor3 >> 3; | ||
286 | baud_value |= divfrac [divisor3 & 0x7] << 14; | ||
287 | baud_index = divindex[divisor3 & 0x7]; | ||
288 | |||
289 | /* Deal with special cases for highest baud rates. */ | ||
290 | if(baud_value == 1) baud_value = 0; | ||
291 | else // 1.0 | ||
292 | if(baud_value == 0x4001) baud_value = 1; // 1.5 | ||
293 | } | ||
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); | ||
297 | } | ||
298 | |||
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); | ||
301 | } | ||
302 | |||
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); | ||
305 | } | ||
306 | |||
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); | ||
309 | } | ||
310 | |||
311 | uint8_t FTDI::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) { | ||
312 | return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); | ||
313 | } | ||
314 | |||
315 | uint8_t FTDI::SndData(uint16_t nbytes, uint8_t *dataptr) { | ||
316 | return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); | ||
317 | } | ||
318 | |||
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); | ||
334 | } | ||