1 /*
2 * Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com
3 * MAX3421E USB host controller support
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the authors nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /* USB functions */
31
32 #include "Usb.h"
33
34 static byte usb_error = 0;
35 static byte usb_task_state;
36 DEV_RECORD devtable[ USB_NUMDEVICES + 1 ];
37 EP_RECORD dev0ep; //Endpoint data structure used during enumeration for uninitialized device
38
39
40 /* constructor */
41
USB()42 USB::USB () {
43 usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine
44 init();
45 }
46 /* Initialize data structures */
init()47 void USB::init()
48 {
49 byte i;
50 for( i = 0; i < ( USB_NUMDEVICES + 1 ); i++ ) {
51 devtable[ i ].epinfo = NULL; //clear device table
52 devtable[ i ].devclass = 0;
53 }
54 devtable[ 0 ].epinfo = &dev0ep; //set single ep for uninitialized device
55 // not necessary dev0ep.MaxPktSize = 8; //minimum possible
56 dev0ep.sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0
57 dev0ep.rcvToggle = bmRCVTOG0;
58 }
getUsbTaskState(void)59 byte USB::getUsbTaskState( void )
60 {
61 return( usb_task_state );
62 }
setUsbTaskState(byte state)63 void USB::setUsbTaskState( byte state )
64 {
65 usb_task_state = state;
66 }
getDevTableEntry(byte addr,byte ep)67 EP_RECORD* USB::getDevTableEntry( byte addr, byte ep )
68 {
69 EP_RECORD* ptr;
70 ptr = devtable[ addr ].epinfo;
71 ptr += ep;
72 return( ptr );
73 }
74 /* set device table entry */
75 /* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
setDevTableEntry(byte addr,EP_RECORD * eprecord_ptr)76 void USB::setDevTableEntry( byte addr, EP_RECORD* eprecord_ptr )
77 {
78 devtable[ addr ].epinfo = eprecord_ptr;
79 //return();
80 }
81 /* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */
82 /* depending on request. Actual requests are defined as inlines */
83 /* return codes: */
84 /* 00 = success */
85 /* 01-0f = non-zero HRSLT */
ctrlReq(byte addr,byte ep,byte bmReqType,byte bRequest,byte wValLo,byte wValHi,unsigned int wInd,unsigned int nbytes,char * dataptr,unsigned int nak_limit)86 byte USB::ctrlReq( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, unsigned int nbytes, char* dataptr, unsigned int nak_limit )
87 {
88 boolean direction = false; //request direction, IN or OUT
89 byte rcode;
90 SETUP_PKT setup_pkt;
91
92 regWr( rPERADDR, addr ); //set peripheral address
93 if( bmReqType & 0x80 ) {
94 direction = true; //determine request direction
95 }
96 /* fill in setup packet */
97 setup_pkt.ReqType_u.bmRequestType = bmReqType;
98 setup_pkt.bRequest = bRequest;
99 setup_pkt.wVal_u.wValueLo = wValLo;
100 setup_pkt.wVal_u.wValueHi = wValHi;
101 setup_pkt.wIndex = wInd;
102 setup_pkt.wLength = nbytes;
103 bytesWr( rSUDFIFO, 8, ( char *)&setup_pkt ); //transfer to setup packet FIFO
104 rcode = dispatchPkt( tokSETUP, ep, nak_limit ); //dispatch packet
105 //Serial.println("Setup packet"); //DEBUG
106 if( rcode ) { //return HRSLT if not zero
107 Serial.print("Setup packet error: ");
108 Serial.print( rcode, HEX );
109 return( rcode );
110 }
111 //Serial.println( direction, HEX );
112 if( dataptr != NULL ) { //data stage, if present
113 rcode = ctrlData( addr, ep, nbytes, dataptr, direction );
114 }
115 if( rcode ) { //return error
116 Serial.print("Data packet error: ");
117 Serial.print( rcode, HEX );
118 return( rcode );
119 }
120 rcode = ctrlStatus( ep, direction ); //status stage
121 return( rcode );
122 }
123 /* Control transfer with status stage and no data stage */
124 /* Assumed peripheral address is already set */
ctrlStatus(byte ep,boolean direction,unsigned int nak_limit)125 byte USB::ctrlStatus( byte ep, boolean direction, unsigned int nak_limit )
126 {
127 byte rcode;
128 if( direction ) { //GET
129 rcode = dispatchPkt( tokOUTHS, ep, nak_limit );
130 }
131 else {
132 rcode = dispatchPkt( tokINHS, ep, nak_limit );
133 }
134 return( rcode );
135 }
136 /* Control transfer with data stage. Stages 2 and 3 of control transfer. Assumes preipheral address is set and setup packet has been sent */
ctrlData(byte addr,byte ep,unsigned int nbytes,char * dataptr,boolean direction,unsigned int nak_limit)137 byte USB::ctrlData( byte addr, byte ep, unsigned int nbytes, char* dataptr, boolean direction, unsigned int nak_limit )
138 {
139 byte rcode;
140 if( direction ) { //IN transfer
141 devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
142 rcode = inTransfer( addr, ep, nbytes, dataptr, nak_limit );
143 return( rcode );
144 }
145 else { //OUT transfer
146 devtable[ addr ].epinfo[ ep ].sndToggle = bmSNDTOG1;
147 rcode = outTransfer( addr, ep, nbytes, dataptr, nak_limit );
148 return( rcode );
149 }
150 }
151 /* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
152 /* Keep sending INs and writes data to memory area pointed by 'data' */
153 /* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
154 fe USB xfer timeout */
inTransfer(byte addr,byte ep,unsigned int nbytes,char * data,unsigned int nak_limit)155 byte USB::inTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit )
156 {
157 byte rcode;
158 byte pktsize;
159 byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize;
160 unsigned int xfrlen = 0;
161 regWr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle ); //set toggle value
162 while( 1 ) { // use a 'return' to exit this loop
163 rcode = dispatchPkt( tokIN, ep, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS.
164 if( rcode ) {
165 return( rcode ); //should be 0, indicating ACK. Else return error code.
166 }
167 /* check for RCVDAVIRQ and generate error if not present */
168 /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */
169 if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) {
170 return ( 0xf0 ); //receive error
171 }
172 pktsize = regRd( rRCVBC ); //number of received bytes
173 data = bytesRd( rRCVFIFO, pktsize, data );
174 regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer
175 xfrlen += pktsize; // add this packet's byte count to total transfer length
176 /* The transfer is complete under two conditions: */
177 /* 1. The device sent a short packet (L.T. maxPacketSize) */
178 /* 2. 'nbytes' have been transferred. */
179 if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes?
180 if( regRd( rHRSL ) & bmRCVTOGRD ) { //save toggle value
181 devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
182 }
183 else {
184 devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0;
185 }
186 return( 0 );
187 }
188 }//while( 1 )
189 }
190
newInTransfer(byte addr,byte ep,unsigned int nbytes,char * data,unsigned int nak_limit)191 int USB::newInTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit )
192 {
193 byte rcode;
194 byte pktsize;
195 byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize;
196 unsigned int xfrlen = 0;
197 regWr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle ); //set toggle value
198 while( 1 ) { // use a 'return' to exit this loop
199 rcode = dispatchPkt( tokIN, ep, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS.
200 if( rcode ) {
201 return -1; //should be 0, indicating ACK. Else return error code.
202 }
203 /* check for RCVDAVIRQ and generate error if not present */
204 /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */
205 if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) {
206 return -1; //receive error
207 }
208 pktsize = regRd( rRCVBC ); //number of received bytes
209 data = bytesRd( rRCVFIFO, pktsize, data );
210 regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer
211 xfrlen += pktsize; // add this packet's byte count to total transfer length
212 /* The transfer is complete under two conditions: */
213 /* 1. The device sent a short packet (L.T. maxPacketSize) */
214 /* 2. 'nbytes' have been transferred. */
215 if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes?
216 if( regRd( rHRSL ) & bmRCVTOGRD ) { //save toggle value
217 devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
218 }
219 else {
220 devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0;
221 }
222 return xfrlen;
223 }
224 }//while( 1 )
225 }
226
227 /* OUT transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
228 /* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */
229 /* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
230 /* major part of this function borrowed from code shared by Richard Ibbotson */
outTransfer(byte addr,byte ep,unsigned int nbytes,char * data,unsigned int nak_limit)231 byte USB::outTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit )
232 {
233 byte rcode, retry_count;
234 char* data_p = data; //local copy of the data pointer
235 unsigned int bytes_tosend, nak_count;
236 unsigned int bytes_left = nbytes;
237 byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize;
238 unsigned long timeout = millis() + USB_XFER_TIMEOUT;
239
240 if (!maxpktsize) { //todo: move this check close to epinfo init. Make it 1< pktsize <64
241 return 0xFE;
242 }
243
244 regWr( rHCTL, devtable[ addr ].epinfo[ ep ].sndToggle ); //set toggle value
245 while( bytes_left ) {
246 retry_count = 0;
247 nak_count = 0;
248 bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
249 bytesWr( rSNDFIFO, bytes_tosend, data_p ); //filling output FIFO
250 regWr( rSNDBC, bytes_tosend ); //set number of bytes
251 regWr( rHXFR, ( tokOUT | ep )); //dispatch packet
252 while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
253 regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
254 rcode = ( regRd( rHRSL ) & 0x0f );
255 while( rcode && ( timeout > millis())) {
256 switch( rcode ) {
257 case hrNAK:
258 nak_count++;
259 if( nak_limit && ( nak_count == USB_NAK_LIMIT )) {
260 return( rcode); //return NAK
261 }
262 break;
263 case hrTIMEOUT:
264 retry_count++;
265 if( retry_count == USB_RETRY_LIMIT ) {
266 return( rcode ); //return TIMEOUT
267 }
268 break;
269 default:
270 return( rcode );
271 }//switch( rcode...
272 /* process NAK according to Host out NAK bug */
273 regWr( rSNDBC, 0 );
274 regWr( rSNDFIFO, *data_p );
275 regWr( rSNDBC, bytes_tosend );
276 regWr( rHXFR, ( tokOUT | ep )); //dispatch packet
277 while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
278 regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
279 rcode = ( regRd( rHRSL ) & 0x0f );
280 }//while( rcode && ....
281 bytes_left -= bytes_tosend;
282 data_p += bytes_tosend;
283 }//while( bytes_left...
284 devtable[ addr ].epinfo[ ep ].sndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? bmSNDTOG1 : bmSNDTOG0; //update toggle
285 return( rcode ); //should be 0 in all cases
286 }
287 /* dispatch usb packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
288 /* If NAK, tries to re-send up to nak_limit times */
289 /* If nak_limit == 0, do not count NAKs, exit after timeout */
290 /* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
291 /* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */
dispatchPkt(byte token,byte ep,unsigned int nak_limit)292 byte USB::dispatchPkt( byte token, byte ep, unsigned int nak_limit )
293 {
294 unsigned long timeout = millis() + USB_XFER_TIMEOUT;
295 byte tmpdata;
296 byte rcode;
297 unsigned int nak_count = 0;
298 char retry_count = 0;
299
300 while( timeout > millis() ) {
301 regWr( rHXFR, ( token|ep )); //launch the transfer
302 rcode = 0xff;
303 while( millis() < timeout ) { //wait for transfer completion
304 tmpdata = regRd( rHIRQ );
305 if( tmpdata & bmHXFRDNIRQ ) {
306 regWr( rHIRQ, bmHXFRDNIRQ ); //clear the interrupt
307 rcode = 0x00;
308 break;
309 }//if( tmpdata & bmHXFRDNIRQ
310 }//while ( millis() < timeout
311 if( rcode != 0x00 ) { //exit if timeout
312 return( rcode );
313 }
314 rcode = ( regRd( rHRSL ) & 0x0f ); //analyze transfer result
315 switch( rcode ) {
316 case hrNAK:
317 nak_count ++;
318 if( nak_limit && ( nak_count == nak_limit )) {
319 return( rcode );
320 }
321 break;
322 case hrTIMEOUT:
323 retry_count ++;
324 if( retry_count == USB_RETRY_LIMIT ) {
325 return( rcode );
326 }
327 break;
328 default:
329 return( rcode );
330 }//switch( rcode
331 }//while( timeout > millis()
332 return( rcode );
333 }
334 /* USB main task. Performs enumeration/cleanup */
Task(void)335 void USB::Task( void ) //USB state machine
336 {
337 byte i;
338 byte rcode;
339 static byte tmpaddr;
340 byte tmpdata;
341 static unsigned long delay = 0;
342 USB_DEVICE_DESCRIPTOR buf;
343 tmpdata = getVbusState();
344 /* modify USB task state if Vbus changed */
345
346 switch( tmpdata ) {
347 case SE1: //illegal state
348 usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
349 break;
350 case SE0: //disconnected
351 if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) {
352 usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
353 }
354 break;
355 case FSHOST: //attached
356 case LSHOST:
357 if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
358 delay = millis() + USB_SETTLE_DELAY;
359 usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
360 }
361 break;
362 }// switch( tmpdata
363 //Serial.print("USB task state: ");
364 //Serial.println( usb_task_state, HEX );
365 switch( usb_task_state ) {
366 case USB_DETACHED_SUBSTATE_INITIALIZE:
367 init();
368 usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
369 break;
370 case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here
371 break;
372 case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here
373 break;
374 case USB_ATTACHED_SUBSTATE_SETTLE: //setlle time for just attached device
375 if( delay < millis() ) {
376 usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
377 }
378 break;
379 case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
380 regWr( rHCTL, bmBUSRST ); //issue bus reset
381 usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
382 break;
383 case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
384 if(( regRd( rHCTL ) & bmBUSRST ) == 0 ) {
385 tmpdata = regRd( rMODE ) | bmSOFKAENAB; //start SOF generation
386 regWr( rMODE, tmpdata );
387 // regWr( rMODE, bmSOFKAENAB );
388 usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
389 delay = millis() + 20; //20ms wait after reset per USB spec
390 }
391 break;
392 case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
393 if( regRd( rHIRQ ) & bmFRAMEIRQ ) { //when first SOF received we can continue
394 if( delay < millis() ) { //20ms passed
395 usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
396 }
397 }
398 break;
399 case USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE:
400 // toggle( BPNT_0 );
401 devtable[ 0 ].epinfo->MaxPktSize = 8; //set max.packet size to min.allowed
402 rcode = getDevDescr( 0, 0, 8, ( char* )&buf );
403 if( rcode == 0 ) {
404 devtable[ 0 ].epinfo->MaxPktSize = buf.bMaxPacketSize0;
405 usb_task_state = USB_STATE_ADDRESSING;
406 }
407 else {
408 usb_error = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
409 usb_task_state = USB_STATE_ERROR;
410 }
411 break;
412 case USB_STATE_ADDRESSING:
413 for( i = 1; i < USB_NUMDEVICES; i++ ) {
414 if( devtable[ i ].epinfo == NULL ) {
415 devtable[ i ].epinfo = devtable[ 0 ].epinfo; //set correct MaxPktSize
416 //temporary record
417 //until plugged with real device endpoint structure
418 rcode = setAddr( 0, 0, i );
419 if( rcode == 0 ) {
420 tmpaddr = i;
421 usb_task_state = USB_STATE_CONFIGURING;
422 }
423 else {
424 usb_error = USB_STATE_ADDRESSING; //set address error
425 usb_task_state = USB_STATE_ERROR;
426 }
427 break; //break if address assigned or error occured during address assignment attempt
428 }
429 }//for( i = 1; i < USB_NUMDEVICES; i++
430 if( usb_task_state == USB_STATE_ADDRESSING ) { //no vacant place in devtable
431 usb_error = 0xfe;
432 usb_task_state = USB_STATE_ERROR;
433 }
434 break;
435 case USB_STATE_CONFIGURING:
436 break;
437 case USB_STATE_RUNNING:
438 break;
439 case USB_STATE_ERROR:
440 break;
441 }// switch( usb_task_state
442 }
443
444