comparison Output/pjrcUSB/arm/usb_dev.c @ 420:23a1868b4ac2

Adding dynamic USB power support - Each scan module now has a current change callback which passes the available current as a parameter - No longer attempts to use the max 500 mA immediately, starts with 100 mA then goes to 500 mA after enumeration - If enumeration fails due to bMaxPower of 500 mA, then attempt again at 100 mA (might also be possible to go even lower to 20 mA in certain cases) - Now working with the Apple Ipad (no over-power messages) - Fixed Wake-up behaviour on Apple Ipad (and likely other iOS devices) - More effecient set_feature/clear_feature handling (device handler) - Initial power handling via Interconnect (still needs work to get it more dynamic)
author Jacob Alexander <haata@kiibohd.com>
date Sun, 21 Feb 2016 19:56:52 -0800
parents d8f61e15aca1
children f10c2dad7f55
comparison
equal deleted inserted replaced
419:910be0f02758 420:23a1868b4ac2
1 /* Teensyduino Core Library 1 /* Teensyduino Core Library
2 * http://www.pjrc.com/teensy/ 2 * http://www.pjrc.com/teensy/
3 * Copyright (c) 2013 PJRC.COM, LLC. 3 * Copyright (c) 2013 PJRC.COM, LLC.
4 * Modifications by Jacob Alexander (2013-2015) 4 * Modifications by Jacob Alexander (2013-2016)
5 * 5 *
6 * Permission is hereby granted, free of charge, to any person obtaining 6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the 7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including 8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish, 9 * without limitation the rights to use, copy, modify, merge, publish,
166 volatile uint8_t usb_configuration = 0; 166 volatile uint8_t usb_configuration = 0;
167 volatile uint8_t usb_reboot_timer = 0; 167 volatile uint8_t usb_reboot_timer = 0;
168 168
169 static uint8_t reply_buffer[8]; 169 static uint8_t reply_buffer[8];
170 170
171 static uint8_t power_neg_delay;
172 static uint32_t power_neg_time;
173
171 174
172 175
173 // ----- Functions ----- 176 // ----- Functions -----
174 177
175 static void endpoint0_stall() 178 static void endpoint0_stall()
184 { 187 {
185 table[index(0, TX, ep0_tx_bdt_bank)].addr = (void *)data; 188 table[index(0, TX, ep0_tx_bdt_bank)].addr = (void *)data;
186 table[index(0, TX, ep0_tx_bdt_bank)].desc = BDT_DESC(len, ep0_tx_data_toggle); 189 table[index(0, TX, ep0_tx_bdt_bank)].desc = BDT_DESC(len, ep0_tx_data_toggle);
187 ep0_tx_data_toggle ^= 1; 190 ep0_tx_data_toggle ^= 1;
188 ep0_tx_bdt_bank ^= 1; 191 ep0_tx_bdt_bank ^= 1;
192 }
193
194 // Used to check any USB state changes that may not have a proper interrupt
195 // Called once per scan loop, should take minimal processing time or it may affect other modules
196 void usb_device_check()
197 {
198 // Check to see if we're still waiting for the next USB request after Get Configuration Descriptor
199 // If still waiting, restart the USB initialization with a lower power requirement
200 if ( power_neg_delay )
201 {
202 // Check if 100 ms has elapsed
203 if ( systick_millis_count - power_neg_time > 100 )
204 {
205 // Update bMaxPower
206 // The value set is in increments of 2 mA
207 // So 50 * 2 mA = 100 mA
208 // XXX Currently only transitions to 100 mA
209 // It may be possible to transition down again to 20 mA
210 *usb_bMaxPower = 50;
211
212 // Re-initialize USB
213 power_neg_delay = 0;
214 usb_configuration = 0; // Clear USB configuration if we have one
215 USB0_CONTROL = 0; // Disable D+ Pullup to simulate disconnect
216 delay(10); // Delay is necessary to simulate disconnect
217 usb_init();
218 }
219 }
189 } 220 }
190 221
191 static void usb_setup() 222 static void usb_setup()
192 { 223 {
193 const uint8_t *data = NULL; 224 const uint8_t *data = NULL;
197 volatile uint8_t *reg; 228 volatile uint8_t *reg;
198 uint8_t epconf; 229 uint8_t epconf;
199 const uint8_t *cfg; 230 const uint8_t *cfg;
200 int i; 231 int i;
201 232
233 // If another request is made, disable the power negotiation check
234 // See GET_DESCRIPTOR - Configuration
235 if ( power_neg_delay )
236 {
237 power_neg_delay = 0;
238 }
239
202 switch ( setup.wRequestAndType ) 240 switch ( setup.wRequestAndType )
203 { 241 {
204 case 0x0500: // SET_ADDRESS 242 case 0x0500: // SET_ADDRESS
205 goto send; 243 goto send;
206 244
210 #endif 248 #endif
211 usb_configuration = setup.wValue; 249 usb_configuration = setup.wValue;
212 Output_Available = usb_configuration; 250 Output_Available = usb_configuration;
213 reg = &USB0_ENDPT1; 251 reg = &USB0_ENDPT1;
214 cfg = usb_endpoint_config_table; 252 cfg = usb_endpoint_config_table;
253
254 // Now configured so we can utilize bMaxPower now
255 Output_update_usb_current( *usb_bMaxPower * 2 );
256
215 // clear all BDT entries, free any allocated memory... 257 // clear all BDT entries, free any allocated memory...
216 for ( i = 4; i < ( NUM_ENDPOINTS + 1) * 4; i++ ) 258 for ( i = 4; i < ( NUM_ENDPOINTS + 1) * 4; i++ )
217 { 259 {
218 if ( table[i].desc & BDT_OWN ) 260 if ( table[i].desc & BDT_OWN )
219 { 261 {
322 data = reply_buffer; 364 data = reply_buffer;
323 datalen = 2; 365 datalen = 2;
324 goto send; 366 goto send;
325 367
326 case 0x0100: // CLEAR_FEATURE (device) 368 case 0x0100: // CLEAR_FEATURE (device)
369 switch ( setup.wValue )
370 {
371 // CLEAR_FEATURE(DEVICE_REMOTE_WAKEUP)
372 // See SET_FEATURE(DEVICE_REMOTE_WAKEUP) for details
373 case 0x1:
374 goto send;
375 }
376
377 warn_msg("SET_FEATURE - Device wValue(");
378 printHex( setup.wValue );
379 print( ")" NL );
380 endpoint0_stall();
381 return;
382
327 case 0x0101: // CLEAR_FEATURE (interface) 383 case 0x0101: // CLEAR_FEATURE (interface)
328 // TODO: Currently ignoring, perhaps useful? -HaaTa 384 // TODO: Currently ignoring, perhaps useful? -HaaTa
329 warn_print("CLEAR_FEATURE - Device/Interface"); 385 warn_msg("CLEAR_FEATURE - Interface wValue(");
386 printHex( setup.wValue );
387 print(") wIndex(");
388 printHex( setup.wIndex );
389 print( ")" NL );
330 endpoint0_stall(); 390 endpoint0_stall();
331 return; 391 return;
332 392
333 case 0x0102: // CLEAR_FEATURE (endpoint) 393 case 0x0102: // CLEAR_FEATURE (endpoint)
334 i = setup.wIndex & 0x7F; 394 i = setup.wIndex & 0x7F;
340 (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) &= ~0x02; 400 (*(uint8_t *)(&USB0_ENDPT0 + setup.wIndex * 4)) &= ~0x02;
341 // TODO: do we need to clear the data toggle here? 401 // TODO: do we need to clear the data toggle here?
342 goto send; 402 goto send;
343 403
344 case 0x0300: // SET_FEATURE (device) 404 case 0x0300: // SET_FEATURE (device)
405 switch ( setup.wValue )
406 {
407 // SET_FEATURE(DEVICE_REMOTE_WAKEUP)
408 // XXX: Only used to confirm Remote Wake
409 // Used on Mac OSX and Windows not on Linux
410 // Good post on the behaviour:
411 // http://community.silabs.com/t5/8-bit-MCU/Remote-wakeup-HID/m-p/74957#M30802
412 case 0x1:
413 goto send;
414 }
415
416 warn_msg("SET_FEATURE - Device wValue(");
417 printHex( setup.wValue );
418 print( ")" NL );
419 endpoint0_stall();
420 return;
421
345 case 0x0301: // SET_FEATURE (interface) 422 case 0x0301: // SET_FEATURE (interface)
346 // TODO: Currently ignoring, perhaps useful? -HaaTa 423 // TODO: Currently ignoring, perhaps useful? -HaaTa
347 warn_print("SET_FEATURE - Device/Interface"); 424 warn_msg("SET_FEATURE - Interface wValue(");
425 printHex( setup.wValue );
426 print(") wIndex(");
427 printHex( setup.wIndex );
428 print( ")" NL );
348 endpoint0_stall(); 429 endpoint0_stall();
349 return; 430 return;
350 431
351 case 0x0302: // SET_FEATURE (endpoint) 432 case 0x0302: // SET_FEATURE (endpoint)
352 i = setup.wIndex & 0x7F; 433 i = setup.wIndex & 0x7F;
383 } 464 }
384 else 465 else
385 { 466 {
386 datalen = list->length; 467 datalen = list->length;
387 } 468 }
469
470 // XXX Power negotiation hack -HaaTa
471 // Some devices such as the Apple Ipad do not support bMaxPower greater than 100 mA
472 // However, there is no provision in the basic USB 2.0 stack for power negotiation
473 // To get around this:
474 // * Attempt to set bMaxPower to 500 mA first
475 // * If more than 100 ms passes since retrieving a Get Configuration Descriptor
476 // (Descriptor with bMaxPower in it)
477 // * Change usb_bMaxPower to 50 (100 mA)
478 // * Restart the USB init process
479 // According to notes online, it says that some Apple devices can only do 20 mA
480 // However, in my testing this hasn't been the case
481 // (you can also draw as much current as you want if you just lie in the descriptor :P)
482 // If this becomes an issue we can use this hack a second time to negotiate down to 20 mA
483 // (which should be fine for just the mcu)
484 if ( setup.wValue == 0x0200 && setup.wIndex == 0x0 )
485 {
486 power_neg_delay = 1;
487 power_neg_time = systick_millis_count;
488 }
489
388 #if UART_DEBUG 490 #if UART_DEBUG
389 print("Desc found, "); 491 print("Desc found, ");
390 printHex32( (uint32_t)data ); 492 printHex32( (uint32_t)data );
391 print(","); 493 print(",");
392 printHex( datalen ); 494 printHex( datalen );
860 //#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd)) 962 //#define index(endpoint, tx, odd) (((endpoint) << 2) | ((tx) << 1) | (odd))
861 //#define stat2bufferdescriptor(stat) (table + ((stat) >> 2)) 963 //#define stat2bufferdescriptor(stat) (table + ((stat) >> 2))
862 964
863 void usb_tx( uint32_t endpoint, usb_packet_t *packet ) 965 void usb_tx( uint32_t endpoint, usb_packet_t *packet )
864 { 966 {
967 // Since we are transmitting data, USB will be brought out of sleep/suspend
968 // if it's in that state
969 // Use the currently set descriptor value
970 Output_update_usb_current( *usb_bMaxPower * 2 );
971
865 bdt_t *b = &table[ index( endpoint, TX, EVEN ) ]; 972 bdt_t *b = &table[ index( endpoint, TX, EVEN ) ];
866 uint8_t next; 973 uint8_t next;
867 974
868 endpoint--; 975 endpoint--;
869 if ( endpoint >= NUM_ENDPOINTS ) 976 if ( endpoint >= NUM_ENDPOINTS )
1159 //serial_phex(err); 1266 //serial_phex(err);
1160 //serial_print("\n"); 1267 //serial_print("\n");
1161 USB0_ISTAT = USB_ISTAT_ERROR; 1268 USB0_ISTAT = USB_ISTAT_ERROR;
1162 } 1269 }
1163 1270
1271 // USB Host signalling device to enter 'sleep' state
1272 // The USB Module triggers this interrupt when it detects the bus has been idle for 3 ms
1164 if ( (status & USB_ISTAT_SLEEP /* 10 */ ) ) 1273 if ( (status & USB_ISTAT_SLEEP /* 10 */ ) )
1165 { 1274 {
1166 //serial_print("sleep\n"); 1275 info_print("Host has requested USB sleep/suspend state");
1276 Output_update_usb_current( 100 ); // Set to 100 mA
1167 USB0_ISTAT = USB_ISTAT_SLEEP; 1277 USB0_ISTAT = USB_ISTAT_SLEEP;
1168 } 1278 }
1169 } 1279 }
1170 1280
1171 1281
1218 NVIC_ENABLE_IRQ( IRQ_USBOTG ); 1328 NVIC_ENABLE_IRQ( IRQ_USBOTG );
1219 1329
1220 // enable d+ pullup 1330 // enable d+ pullup
1221 USB0_CONTROL = USB_CONTROL_DPPULLUPNONOTG; 1331 USB0_CONTROL = USB_CONTROL_DPPULLUPNONOTG;
1222 1332
1333 // Do not check for power negotiation delay until Get Configuration Descriptor
1334 power_neg_delay = 0;
1335
1223 return 1; 1336 return 1;
1224 } 1337 }
1225 1338
1226 // return 0 if the USB is not configured, or the configuration 1339 // return 0 if the USB is not configured, or the configuration
1227 // number selected by the HOST 1340 // number selected by the HOST