diff options
Diffstat (limited to 'firmware/usb.c')
-rw-r--r-- | firmware/usb.c | 597 |
1 files changed, 325 insertions, 272 deletions
diff --git a/firmware/usb.c b/firmware/usb.c index d9d9f11031..59edd680df 100644 --- a/firmware/usb.c +++ b/firmware/usb.c | |||
@@ -57,13 +57,19 @@ | |||
57 | #define USB_FULL_INIT | 57 | #define USB_FULL_INIT |
58 | #endif | 58 | #endif |
59 | 59 | ||
60 | #if defined(USB_DETECT_BY_DRV) || defined(USB_DETECT_BY_CORE) | ||
61 | /* These aren't treated differently here */ | ||
62 | #define USB_DELAYED_INSERT | ||
63 | #endif | ||
64 | |||
60 | #ifdef HAVE_LCD_BITMAP | 65 | #ifdef HAVE_LCD_BITMAP |
61 | bool do_screendump_instead_of_usb = false; | 66 | bool do_screendump_instead_of_usb = false; |
62 | #endif | 67 | #endif |
63 | 68 | ||
64 | #if !defined(SIMULATOR) && !defined(USB_NONE) | 69 | #if !defined(SIMULATOR) && !defined(USB_NONE) |
65 | 70 | ||
66 | static int usb_state; | 71 | /* We assume that the USB cable is extracted */ |
72 | static int usb_state = USB_EXTRACTED; | ||
67 | 73 | ||
68 | #if (CONFIG_STORAGE & STORAGE_MMC) && defined(USB_FULL_INIT) | 74 | #if (CONFIG_STORAGE & STORAGE_MMC) && defined(USB_FULL_INIT) |
69 | static int usb_mmc_countdown = 0; | 75 | static int usb_mmc_countdown = 0; |
@@ -74,21 +80,12 @@ static int usb_mmc_countdown = 0; | |||
74 | static long usb_stack[(DEFAULT_STACK_SIZE + SECTOR_SIZE + DUMP_BMP_LINESIZE)/sizeof(long)]; | 80 | static long usb_stack[(DEFAULT_STACK_SIZE + SECTOR_SIZE + DUMP_BMP_LINESIZE)/sizeof(long)]; |
75 | static const char usb_thread_name[] = "usb"; | 81 | static const char usb_thread_name[] = "usb"; |
76 | static unsigned int usb_thread_entry = 0; | 82 | static unsigned int usb_thread_entry = 0; |
77 | #ifndef USB_STATUS_BY_EVENT | ||
78 | #define NUM_POLL_READINGS (HZ/5) | ||
79 | static int countdown; | ||
80 | #endif /* USB_STATUS_BY_EVENT */ | ||
81 | #endif /* USB_FULL_INIT */ | 83 | #endif /* USB_FULL_INIT */ |
82 | static struct event_queue usb_queue; | 84 | static struct event_queue usb_queue; |
83 | static bool usb_monitor_enabled; | 85 | static bool usb_monitor_enabled = false; |
84 | static int last_usb_status; | 86 | static bool exclusive_storage_access = false; |
85 | #ifdef HAVE_USBSTACK | 87 | #ifdef USB_ENABLE_HID |
86 | static bool exclusive_storage_access; | 88 | static bool usb_hid = true; |
87 | #endif | ||
88 | |||
89 | #ifdef USB_FIREWIRE_HANDLING | ||
90 | static int firewire_countdown; | ||
91 | static bool last_firewire_status; | ||
92 | #endif | 89 | #endif |
93 | 90 | ||
94 | #ifdef USB_FULL_INIT | 91 | #ifdef USB_FULL_INIT |
@@ -118,14 +115,93 @@ static void try_reboot(void) | |||
118 | } | 115 | } |
119 | #endif /* USB_FIRWIRE_HANDLING || (HAVE_USBSTACK && !USE_ROCKBOX_USB) */ | 116 | #endif /* USB_FIRWIRE_HANDLING || (HAVE_USBSTACK && !USE_ROCKBOX_USB) */ |
120 | 117 | ||
118 | |||
119 | #ifdef HAVE_LCD_BITMAP | ||
120 | static inline bool usb_do_screendump(void) | ||
121 | { | ||
122 | if(do_screendump_instead_of_usb) | ||
123 | { | ||
124 | usb_state = USB_SCREENDUMP; | ||
125 | screen_dump(); | ||
126 | #ifdef HAVE_REMOTE_LCD | ||
127 | remote_screen_dump(); | ||
128 | #endif | ||
129 | return true; | ||
130 | } | ||
131 | |||
132 | return false; | ||
133 | } | ||
134 | #else /* !HAVE_LCD_BITMAP */ | ||
135 | static inline bool usb_do_screendump(void) | ||
136 | { | ||
137 | return false; | ||
138 | } | ||
139 | #endif /* HAVE_LCD_BITMAP */ | ||
140 | |||
141 | |||
121 | #ifdef HAVE_USBSTACK | 142 | #ifdef HAVE_USBSTACK |
122 | /* inline since branch is chosen at compile time */ | 143 | static inline bool usb_configure_drivers(int for_state) |
123 | static inline void usb_slave_mode(bool on) | ||
124 | { | 144 | { |
145 | switch(for_state) | ||
146 | { | ||
147 | case USB_POWERED: | ||
148 | #ifdef USB_ENABLE_STORAGE | ||
149 | usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, false); | ||
150 | #endif | ||
151 | #ifdef USB_ENABLE_HID | ||
152 | #ifdef USB_ENABLE_CHARGING_ONLY | ||
153 | usb_core_enable_driver(USB_DRIVER_HID, false); | ||
154 | #else | ||
155 | usb_core_enable_driver(USB_DRIVER_HID, true); | ||
156 | #endif /* USB_ENABLE_CHARGING_ONLY */ | ||
157 | #endif /* USB_ENABLE_HID */ | ||
158 | |||
159 | #ifdef USB_ENABLE_CHARGING_ONLY | ||
160 | usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true); | ||
161 | #endif | ||
162 | exclusive_storage_access = false; | ||
163 | |||
164 | usb_attach(); /* Powered only: attach now. */ | ||
165 | break; | ||
166 | /* USB_POWERED: */ | ||
167 | |||
168 | case USB_INSERTED: | ||
169 | #ifdef USB_ENABLE_STORAGE | ||
170 | usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, true); | ||
171 | #endif | ||
172 | #ifdef USB_ENABLE_HID | ||
173 | usb_core_enable_driver(USB_DRIVER_HID, usb_hid); | ||
174 | #endif | ||
175 | #ifdef USB_ENABLE_CHARGING_ONLY | ||
176 | usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false); | ||
177 | #endif | ||
178 | /* Check any drivers enabled at this point for exclusive storage | ||
179 | * access requirements. */ | ||
180 | exclusive_storage_access = usb_core_any_exclusive_storage(); | ||
181 | |||
182 | if(exclusive_storage_access) | ||
183 | return true; | ||
184 | |||
185 | usb_attach(); /* Not exclusive: attach now. */ | ||
186 | break; | ||
187 | /* USB_INSERTED: */ | ||
188 | |||
189 | case USB_EXTRACTED: | ||
190 | if(exclusive_storage_access) | ||
191 | usb_release_exclusive_storage(); | ||
192 | break; | ||
193 | /* USB_EXTRACTED: */ | ||
194 | } | ||
195 | |||
196 | return false; | ||
197 | } | ||
198 | |||
125 | #ifdef USE_ROCKBOX_USB | 199 | #ifdef USE_ROCKBOX_USB |
200 | static inline void usb_slave_mode(bool on) | ||
201 | { | ||
126 | int rc; | 202 | int rc; |
127 | 203 | ||
128 | if (on) | 204 | if(on) |
129 | { | 205 | { |
130 | trigger_cpu_boost(); | 206 | trigger_cpu_boost(); |
131 | #ifdef HAVE_PRIORITY_SCHEDULING | 207 | #ifdef HAVE_PRIORITY_SCHEDULING |
@@ -136,36 +212,72 @@ static inline void usb_slave_mode(bool on) | |||
136 | } | 212 | } |
137 | else /* usb_state == USB_INSERTED (only!) */ | 213 | else /* usb_state == USB_INSERTED (only!) */ |
138 | { | 214 | { |
139 | #if !defined(USB_DETECT_BY_DRV) && !defined(USB_DETECT_BY_CORE) | ||
140 | usb_enable(false); | 215 | usb_enable(false); |
141 | #endif | ||
142 | #ifdef HAVE_PRIORITY_SCHEDULING | 216 | #ifdef HAVE_PRIORITY_SCHEDULING |
143 | thread_set_priority(THREAD_ID_CURRENT, PRIORITY_SYSTEM); | 217 | thread_set_priority(THREAD_ID_CURRENT, PRIORITY_SYSTEM); |
144 | #endif | 218 | #endif |
145 | /* Entered exclusive mode */ | 219 | /* Entered exclusive mode */ |
146 | rc = disk_mount_all(); | 220 | rc = disk_mount_all(); |
147 | if (rc <= 0) /* no partition */ | 221 | if(rc <= 0) /* no partition */ |
148 | panicf("mount: %d",rc); | 222 | panicf("mount: %d",rc); |
149 | 223 | ||
150 | cancel_cpu_boost(); | 224 | cancel_cpu_boost(); |
151 | } | 225 | } |
152 | #else /* !USE_ROCKBOX_USB */ | 226 | } |
153 | if (on) | 227 | |
228 | #ifdef HAVE_HOTSWAP | ||
229 | static inline void usb_handle_hotswap(long id) | ||
230 | { | ||
231 | switch(id) | ||
232 | { | ||
233 | case SYS_HOTSWAP_INSERTED: | ||
234 | case SYS_HOTSWAP_EXTRACTED: | ||
235 | usb_core_hotswap_event(1, id == SYS_HOTSWAP_INSERTED); | ||
236 | break; | ||
237 | } | ||
238 | /* Note: No MMC storage handling is needed with the stack atm. */ | ||
239 | } | ||
240 | #endif /* HAVE_HOTSWAP */ | ||
241 | |||
242 | #else /* !USB_ROCKBOX_USB */ | ||
243 | static inline void usb_slave_mode(bool on) | ||
244 | { | ||
245 | if(on) | ||
154 | { | 246 | { |
155 | /* until we have native mass-storage mode, we want to reboot on | 247 | /* until we have native mass-storage mode, we want to reboot on |
156 | usb host connect */ | 248 | usb host connect */ |
157 | try_reboot(); | 249 | try_reboot(); |
158 | } | 250 | } |
159 | #endif /* USE_ROCKBOX_USB */ | ||
160 | } | 251 | } |
252 | #endif /* USE_ROCKBOX_USB */ | ||
161 | 253 | ||
162 | void usb_signal_transfer_completion( | 254 | void usb_signal_transfer_completion( |
163 | struct usb_transfer_completion_event_data* event_data) | 255 | struct usb_transfer_completion_event_data* event_data) |
164 | { | 256 | { |
165 | queue_post(&usb_queue, USB_TRANSFER_COMPLETION, (intptr_t)event_data); | 257 | queue_post(&usb_queue, USB_TRANSFER_COMPLETION, (intptr_t)event_data); |
166 | } | 258 | } |
259 | |||
167 | #else /* !HAVE_USBSTACK */ | 260 | #else /* !HAVE_USBSTACK */ |
168 | /* inline since branch is chosen at compile time */ | 261 | |
262 | static inline bool usb_configure_drivers(int for_state) | ||
263 | { | ||
264 | switch(for_state) | ||
265 | { | ||
266 | case USB_POWERED: | ||
267 | exclusive_storage_access = false; | ||
268 | break; | ||
269 | case USB_INSERTED: | ||
270 | exclusive_storage_access = true; | ||
271 | return true; | ||
272 | case USB_EXTRACTED: | ||
273 | if(exclusive_storage_access) | ||
274 | usb_release_exclusive_storage(); | ||
275 | break; | ||
276 | } | ||
277 | |||
278 | return false; | ||
279 | } | ||
280 | |||
169 | static inline void usb_slave_mode(bool on) | 281 | static inline void usb_slave_mode(bool on) |
170 | { | 282 | { |
171 | int rc; | 283 | int rc; |
@@ -196,10 +308,34 @@ static inline void usb_slave_mode(bool on) | |||
196 | panicf("storage: %d",rc); | 308 | panicf("storage: %d",rc); |
197 | 309 | ||
198 | rc = disk_mount_all(); | 310 | rc = disk_mount_all(); |
199 | if (rc <= 0) /* no partition */ | 311 | if(rc <= 0) /* no partition */ |
200 | panicf("mount: %d",rc); | 312 | panicf("mount: %d",rc); |
201 | } | 313 | } |
202 | } | 314 | } |
315 | |||
316 | #ifdef HAVE_HOTSWAP | ||
317 | static inline void usb_handle_hotswap(long id) | ||
318 | { | ||
319 | #if (CONFIG_STORAGE & STORAGE_MMC) | ||
320 | switch(id) | ||
321 | { | ||
322 | case SYS_HOTSWAP_INSERTED: | ||
323 | case SYS_HOTSWAP_EXTRACTED: | ||
324 | if(usb_state == USB_INSERTED) | ||
325 | { | ||
326 | usb_enable(false); | ||
327 | usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */ | ||
328 | } | ||
329 | break; | ||
330 | case USB_REENABLE: | ||
331 | if(usb_state == USB_INSERTED) | ||
332 | usb_enable(true); /* reenable only if still inserted */ | ||
333 | break; | ||
334 | } | ||
335 | #endif /* STORAGE_MMC */ | ||
336 | (void)id; | ||
337 | } | ||
338 | #endif /* HAVE_HOTSWAP */ | ||
203 | #endif /* HAVE_USBSTACK */ | 339 | #endif /* HAVE_USBSTACK */ |
204 | 340 | ||
205 | #ifdef HAVE_USB_POWER | 341 | #ifdef HAVE_USB_POWER |
@@ -218,15 +354,27 @@ static inline bool usb_reboot_button(void) | |||
218 | return (button_status() & ~USBPOWER_BTN_IGNORE) != USBPOWER_BUTTON; | 354 | return (button_status() & ~USBPOWER_BTN_IGNORE) != USBPOWER_BUTTON; |
219 | } | 355 | } |
220 | #endif | 356 | #endif |
221 | #endif /* HAVE_USB_POWER */ | 357 | #else /* !HAVE_USB_POWER */ |
358 | static inline bool usb_power_button(void) | ||
359 | { | ||
360 | return false; | ||
361 | } | ||
222 | 362 | ||
223 | #ifdef USB_ENABLE_HID | 363 | #ifdef USB_FIREWIRE_HANDLING |
224 | static bool usb_hid = true; | 364 | static inline bool usb_reboot_button(void) |
365 | { | ||
366 | return false; | ||
367 | } | ||
225 | #endif | 368 | #endif |
369 | #endif /* HAVE_USB_POWER */ | ||
226 | 370 | ||
371 | #ifndef USB_DRIVER_CLOSE | ||
372 | static void usb_thread(void) NORETURN_ATTR; | ||
373 | #endif | ||
227 | static void usb_thread(void) | 374 | static void usb_thread(void) |
228 | { | 375 | { |
229 | int num_acks_to_expect = 0; | 376 | int num_acks_to_expect = 0; |
377 | long last_broadcast_tick = current_tick; | ||
230 | struct queue_event ev; | 378 | struct queue_event ev; |
231 | 379 | ||
232 | while(1) | 380 | while(1) |
@@ -234,216 +382,150 @@ static void usb_thread(void) | |||
234 | queue_wait(&usb_queue, &ev); | 382 | queue_wait(&usb_queue, &ev); |
235 | switch(ev.id) | 383 | switch(ev.id) |
236 | { | 384 | { |
237 | #ifdef USB_DRIVER_CLOSE | 385 | /*** Main USB thread duties ***/ |
238 | case USB_QUIT: | 386 | |
239 | return; | ||
240 | #endif | ||
241 | #ifdef HAVE_USBSTACK | 387 | #ifdef HAVE_USBSTACK |
242 | case USB_TRANSFER_COMPLETION: | 388 | case USB_TRANSFER_COMPLETION: |
243 | usb_core_handle_transfer_completion( | 389 | usb_core_handle_transfer_completion( |
244 | (struct usb_transfer_completion_event_data*)ev.data); | 390 | (struct usb_transfer_completion_event_data*)ev.data); |
391 | break; | ||
392 | #endif /* HAVE_USBSTACK */ | ||
393 | |||
394 | case USB_INSERTED: | ||
395 | #ifdef USB_DELAYED_INSERT | ||
396 | if(usb_state != USB_POWERED) | ||
245 | break; | 397 | break; |
246 | #endif | 398 | #else /* !USB_DELAYED_INSERT */ |
247 | #if defined(USB_DETECT_BY_DRV) || defined(USB_DETECT_BY_CORE) | 399 | if(usb_state != USB_EXTRACTED) |
248 | /* In this case, these events the handle cable insertion USB | ||
249 | * driver determines INSERTED/EXTRACTED state. */ | ||
250 | case USB_POWERED: | ||
251 | /* Set the state to USB_POWERED for now and enable the driver | ||
252 | * to detect a bus reset only. If a bus reset is detected, | ||
253 | * USB_INSERTED will be received. */ | ||
254 | usb_state = USB_POWERED; | ||
255 | usb_enable(true); | ||
256 | break; | 400 | break; |
257 | 401 | ||
258 | case USB_UNPOWERED: | 402 | if(usb_do_screendump()) |
259 | usb_enable(false); | ||
260 | /* This part shouldn't be obligatory for anything that can | ||
261 | * reliably detect removal of the data lines. USB_EXTRACTED | ||
262 | * could be posted on that event while bus power remains | ||
263 | * available. */ | ||
264 | queue_post(&usb_queue, USB_EXTRACTED, 0); | ||
265 | break; | 403 | break; |
266 | #endif /* USB_DETECT_BY_DRV || USB_DETECT_BY_CORE */ | ||
267 | case USB_INSERTED: | ||
268 | #ifdef HAVE_LCD_BITMAP | ||
269 | if(do_screendump_instead_of_usb) | ||
270 | { | ||
271 | usb_state = USB_SCREENDUMP; | ||
272 | screen_dump(); | ||
273 | #ifdef HAVE_REMOTE_LCD | ||
274 | remote_screen_dump(); | ||
275 | #endif | ||
276 | break; | ||
277 | } | ||
278 | #endif | ||
279 | #ifdef HAVE_USB_POWER | ||
280 | if(usb_power_button()) | ||
281 | { | ||
282 | /* Only charging is desired */ | ||
283 | usb_state = USB_POWERED; | ||
284 | #ifdef HAVE_USBSTACK | ||
285 | #ifdef USB_ENABLE_STORAGE | ||
286 | usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, false); | ||
287 | #endif | ||
288 | 404 | ||
289 | #ifdef USB_ENABLE_HID | 405 | usb_state = USB_POWERED; |
290 | #ifdef USB_ENABLE_CHARGING_ONLY | 406 | #endif /* USB_DELAYED_INSERT */ |
291 | usb_core_enable_driver(USB_DRIVER_HID, false); | ||
292 | #else | ||
293 | usb_core_enable_driver(USB_DRIVER_HID, true); | ||
294 | #endif /* USB_ENABLE_CHARGING_ONLY */ | ||
295 | #endif /* USB_ENABLE_HID */ | ||
296 | 407 | ||
297 | #ifdef USB_ENABLE_CHARGING_ONLY | 408 | if(usb_power_button()) |
298 | usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true); | 409 | { |
299 | #endif | 410 | /* Only charging is desired */ |
300 | usb_attach(); | 411 | usb_configure_drivers(USB_POWERED); |
301 | #endif | 412 | break; |
302 | break; | 413 | } |
303 | } | ||
304 | #endif /* HAVE_USB_POWER */ | ||
305 | #ifdef HAVE_USBSTACK | ||
306 | #ifdef HAVE_USB_POWER | ||
307 | /* Set the state to USB_POWERED for now. If permission to connect | ||
308 | * by threads and storage is granted it will be changed to | ||
309 | * USB_CONNECTED. */ | ||
310 | usb_state = USB_POWERED; | ||
311 | #endif | ||
312 | #ifdef USB_ENABLE_STORAGE | ||
313 | usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, true); | ||
314 | #endif | ||
315 | #ifdef USB_ENABLE_HID | ||
316 | usb_core_enable_driver(USB_DRIVER_HID, usb_hid); | ||
317 | #endif | ||
318 | #ifdef USB_ENABLE_CHARGING_ONLY | ||
319 | usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false); | ||
320 | #endif | ||
321 | 414 | ||
322 | /* Check any drivers enabled at this point for exclusive storage | 415 | if(!usb_configure_drivers(USB_INSERTED)) |
323 | * access requirements. */ | 416 | break; /* Exclusive storage access not required */ |
324 | exclusive_storage_access = usb_core_any_exclusive_storage(); | 417 | |
418 | /* Tell all threads that they have to back off the storage. | ||
419 | We subtract one for our own thread. Expect an ACK for every | ||
420 | listener for each broadcast they received. If it has been too | ||
421 | long, the user might have entered a screen that didn't ACK | ||
422 | when inserting the cable, such as a debugging screen. In that | ||
423 | case, reset the count or else USB would be locked out until | ||
424 | rebooting because it most likely won't ever come. Simply | ||
425 | resetting to the most recent broadcast count is racy. */ | ||
426 | if(TIME_AFTER(current_tick, last_broadcast_tick + HZ*5)) | ||
427 | { | ||
428 | num_acks_to_expect = 0; | ||
429 | last_broadcast_tick = current_tick; | ||
430 | } | ||
325 | 431 | ||
326 | if(!exclusive_storage_access) | 432 | num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1; |
327 | { | 433 | DEBUGF("USB inserted. Waiting for %d acks...\n", |
328 | usb_attach(); | 434 | num_acks_to_expect); |
329 | break; | ||
330 | } | ||
331 | #endif /* HAVE_USBSTACK */ | ||
332 | /* Tell all threads that they have to back off the storage. | ||
333 | We subtract one for our own thread. */ | ||
334 | num_acks_to_expect = queue_broadcast(SYS_USB_CONNECTED, 0) - 1; | ||
335 | DEBUGF("USB inserted. Waiting for ack from %d threads...\n", | ||
336 | num_acks_to_expect); | ||
337 | break; | ||
338 | 435 | ||
339 | case SYS_USB_CONNECTED_ACK: | 436 | /* Leave the state as USB_POWERED until the expected number of |
340 | if(num_acks_to_expect > 0 && --num_acks_to_expect == 0) | 437 | ACKS are received. */ |
438 | break; | ||
439 | /* USB_INSERTED: */ | ||
440 | |||
441 | case SYS_USB_CONNECTED_ACK: | ||
442 | if(num_acks_to_expect > 0 && --num_acks_to_expect == 0) | ||
443 | { | ||
444 | DEBUGF("All threads have acknowledged the connect.\n"); | ||
445 | if(usb_state == USB_POWERED) | ||
341 | { | 446 | { |
342 | DEBUGF("All threads have acknowledged the connect.\n"); | ||
343 | usb_slave_mode(true); | 447 | usb_slave_mode(true); |
344 | usb_state = USB_INSERTED; | 448 | usb_state = USB_INSERTED; |
345 | } | 449 | } |
346 | else | 450 | } |
347 | { | 451 | else |
348 | DEBUGF("usb: got ack, %d to go...\n", | 452 | { |
349 | num_acks_to_expect); | 453 | DEBUGF("usb: got ack, %d to go...\n", |
350 | } | 454 | num_acks_to_expect); |
455 | } | ||
456 | break; | ||
457 | /* SYS_USB_CONNECTED_ACK */ | ||
458 | |||
459 | #ifdef USB_DELAYED_INSERT | ||
460 | /* In this case, these events handle cable insertion. USB driver or | ||
461 | core determines USB_INSERTED. */ | ||
462 | case USB_POWERED: | ||
463 | if(usb_state != USB_EXTRACTED) | ||
351 | break; | 464 | break; |
352 | 465 | ||
353 | case USB_EXTRACTED: | 466 | if(usb_do_screendump()) |
354 | #ifdef HAVE_LCD_BITMAP | 467 | break; |
355 | if(usb_state == USB_SCREENDUMP) | ||
356 | { | ||
357 | usb_state = USB_EXTRACTED; | ||
358 | break; /* Connected for screendump only */ | ||
359 | } | ||
360 | #endif | ||
361 | #ifndef HAVE_USBSTACK /* Stack must undo this if POWERED state was transitional */ | ||
362 | #ifdef HAVE_USB_POWER | ||
363 | if(usb_state == USB_POWERED) | ||
364 | { | ||
365 | usb_state = USB_EXTRACTED; | ||
366 | break; | ||
367 | } | ||
368 | #endif | ||
369 | #endif /* HAVE_USBSTACK */ | ||
370 | if(usb_state == USB_INSERTED) | ||
371 | { | ||
372 | /* Only disable the USB mode if we really have enabled it | ||
373 | some threads might not have acknowledged the | ||
374 | insertion */ | ||
375 | usb_slave_mode(false); | ||
376 | } | ||
377 | |||
378 | usb_state = USB_EXTRACTED; | ||
379 | #ifdef HAVE_USBSTACK | ||
380 | if(!exclusive_storage_access) | ||
381 | { | ||
382 | #if !defined(USB_DETECT_BY_DRV) && !defined(USB_DETECT_BY_CORE) | ||
383 | /* Disabled handling USB_UNPOWERED */ | ||
384 | usb_enable(false); | ||
385 | #endif | ||
386 | break; | ||
387 | } | ||
388 | 468 | ||
389 | #endif /* HAVE_USBSTACK */ | 469 | usb_state = USB_POWERED; |
390 | num_acks_to_expect = usb_release_exclusive_storage(); | 470 | usb_enable(true); |
471 | break; | ||
472 | /* USB_POWERED: */ | ||
391 | 473 | ||
474 | case USB_UNPOWERED: | ||
475 | if(usb_state == USB_POWERED) | ||
476 | usb_enable(false); | ||
477 | /* Fall-through - other legal states can be USB_INSERTED or | ||
478 | USB_SCREENDUMP */ | ||
479 | #endif /* USB_DELAYED_INSERT */ | ||
480 | case USB_EXTRACTED: | ||
481 | if(usb_state == USB_EXTRACTED) | ||
392 | break; | 482 | break; |
393 | 483 | ||
394 | case SYS_USB_DISCONNECTED_ACK: | 484 | usb_configure_drivers(USB_EXTRACTED); |
395 | if(num_acks_to_expect > 0 && --num_acks_to_expect == 0) | ||
396 | { | ||
397 | DEBUGF("All threads have acknowledged. " | ||
398 | "We're in business.\n"); | ||
399 | } | ||
400 | else | ||
401 | { | ||
402 | DEBUGF("usb: got ack, %d to go...\n", | ||
403 | num_acks_to_expect); | ||
404 | } | ||
405 | break; | ||
406 | 485 | ||
407 | #ifdef HAVE_HOTSWAP | 486 | /* Only disable the USB slave mode if we really have enabled |
408 | case SYS_HOTSWAP_INSERTED: | 487 | it. Some expected acks may not have been received. */ |
409 | case SYS_HOTSWAP_EXTRACTED: | 488 | if(usb_state == USB_INSERTED) |
410 | #ifdef HAVE_USBSTACK | 489 | usb_slave_mode(false); |
411 | usb_core_hotswap_event(1,ev.id == SYS_HOTSWAP_INSERTED); | 490 | |
412 | #else /* !HAVE_USBSTACK */ | 491 | usb_state = USB_EXTRACTED; |
413 | if(usb_state == USB_INSERTED) | 492 | break; |
414 | { | 493 | /* USB_UNPOWERED: USB_EXTRACTED: */ |
415 | #if (CONFIG_STORAGE & STORAGE_MMC) | ||
416 | usb_enable(false); | ||
417 | usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */ | ||
418 | #endif /* STORAGE_MMC */ | ||
419 | } | ||
420 | #endif /* HAVE_USBSTACK */ | ||
421 | break; | ||
422 | 494 | ||
495 | /*** Miscellaneous USB thread duties ***/ | ||
496 | |||
497 | /* HOTSWAP */ | ||
498 | #ifdef HAVE_HOTSWAP | ||
499 | case SYS_HOTSWAP_INSERTED: | ||
500 | case SYS_HOTSWAP_EXTRACTED: | ||
423 | #if (CONFIG_STORAGE & STORAGE_MMC) | 501 | #if (CONFIG_STORAGE & STORAGE_MMC) |
424 | case USB_REENABLE: | 502 | case USB_REENABLE: |
425 | if(usb_state == USB_INSERTED) | 503 | #endif |
426 | usb_enable(true); /* reenable only if still inserted */ | 504 | usb_handle_hotswap(ev.id); |
427 | break; | 505 | #endif |
428 | #endif /* STORAGE_MMC */ | ||
429 | #endif /* HAVE_HOTSWAP */ | ||
430 | 506 | ||
507 | /* FIREWIRE */ | ||
431 | #ifdef USB_FIREWIRE_HANDLING | 508 | #ifdef USB_FIREWIRE_HANDLING |
432 | case USB_REQUEST_REBOOT: | 509 | case USB_REQUEST_REBOOT: |
433 | #ifdef HAVE_USB_POWER | 510 | if(usb_reboot_button()) |
434 | if (usb_reboot_button()) | 511 | try_reboot(); |
512 | break; | ||
435 | #endif | 513 | #endif |
436 | try_reboot(); | ||
437 | break; | ||
438 | #endif /* USB_FIREWIRE_HANDLING */ | ||
439 | 514 | ||
515 | /* CHARGING */ | ||
440 | #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK) | 516 | #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK) |
441 | case USB_CHARGER_UPDATE: | 517 | case USB_CHARGER_UPDATE: |
442 | usb_charging_maxcurrent_change(usb_charging_maxcurrent()); | 518 | usb_charging_maxcurrent_change(usb_charging_maxcurrent()); |
443 | break; | 519 | break; |
444 | #endif | 520 | #endif |
445 | } | 521 | |
446 | } | 522 | /* CLOSE */ |
523 | #ifdef USB_DRIVER_CLOSE | ||
524 | case USB_QUIT: | ||
525 | return; | ||
526 | #endif | ||
527 | } /* switch */ | ||
528 | } /* while */ | ||
447 | } | 529 | } |
448 | 530 | ||
449 | #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK) | 531 | #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK) |
@@ -460,18 +542,13 @@ void usb_status_event(int current_status) | |||
460 | * current_status: | 542 | * current_status: |
461 | * USB_DETECT_BY_DRV/CORE: USB_POWERED, USB_UNPOWERED, | 543 | * USB_DETECT_BY_DRV/CORE: USB_POWERED, USB_UNPOWERED, |
462 | USB_INSERTED (driver/core) | 544 | USB_INSERTED (driver/core) |
463 | * else: USB_INSERTED, USB_EXTRACTED | 545 | * else: USB_INSERTED, USB_EXTRACTED |
464 | */ | 546 | */ |
465 | if(usb_monitor_enabled) | 547 | if(usb_monitor_enabled) |
466 | { | 548 | { |
467 | int oldstatus = disable_irq_save(); /* Dual-use function */ | 549 | int oldstatus = disable_irq_save(); /* Dual-use function */ |
468 | 550 | queue_remove_from_head(&usb_queue, current_status); | |
469 | if(last_usb_status != current_status) | 551 | queue_post(&usb_queue, current_status, 0); |
470 | { | ||
471 | last_usb_status = current_status; | ||
472 | queue_post(&usb_queue, current_status, 0); | ||
473 | } | ||
474 | |||
475 | restore_irq(oldstatus); | 552 | restore_irq(oldstatus); |
476 | } | 553 | } |
477 | } | 554 | } |
@@ -486,14 +563,14 @@ void usb_start_monitoring(void) | |||
486 | /* An event may have been missed because it was sent before monitoring | 563 | /* An event may have been missed because it was sent before monitoring |
487 | * was enabled due to the connector already having been inserted before | 564 | * was enabled due to the connector already having been inserted before |
488 | * before or during boot. */ | 565 | * before or during boot. */ |
489 | #if defined(USB_DETECT_BY_DRV) || defined(USB_DETECT_BY_CORE) | 566 | #ifdef USB_DELAYED_INSERT |
490 | /* Filter the status - USB_INSERTED may happen later */ | 567 | /* Filter the status - USB_INSERTED may happen later */ |
491 | status = (status == USB_INSERTED) ? USB_POWERED : USB_UNPOWERED; | 568 | status = (status == USB_INSERTED) ? USB_POWERED : USB_UNPOWERED; |
492 | #endif | 569 | #endif |
493 | usb_status_event(status); | 570 | usb_status_event(status); |
494 | 571 | ||
495 | #ifdef USB_FIREWIRE_HANDLING | 572 | #ifdef USB_FIREWIRE_HANDLING |
496 | if (firewire_detect()) | 573 | if(firewire_detect()) |
497 | usb_firewire_connect_event(); | 574 | usb_firewire_connect_event(); |
498 | #endif | 575 | #endif |
499 | 576 | ||
@@ -506,10 +583,18 @@ void usb_firewire_connect_event(void) | |||
506 | queue_post(&usb_queue, USB_REQUEST_REBOOT, 0); | 583 | queue_post(&usb_queue, USB_REQUEST_REBOOT, 0); |
507 | } | 584 | } |
508 | #endif /* USB_FIREWIRE_HANDLING */ | 585 | #endif /* USB_FIREWIRE_HANDLING */ |
586 | |||
509 | #else /* !USB_STATUS_BY_EVENT */ | 587 | #else /* !USB_STATUS_BY_EVENT */ |
588 | |||
510 | static void usb_tick(void) | 589 | static void usb_tick(void) |
511 | { | 590 | { |
512 | int current_status; | 591 | #define NUM_POLL_READINGS (HZ/5) |
592 | static int usb_countdown = -1; | ||
593 | static int last_usb_status = USB_EXTRACTED; | ||
594 | #ifdef USB_FIREWIRE_HANDLING | ||
595 | static int firewire_countdown = -1; | ||
596 | static int last_firewire_status = false; | ||
597 | #endif | ||
513 | 598 | ||
514 | if(usb_monitor_enabled) | 599 | if(usb_monitor_enabled) |
515 | { | 600 | { |
@@ -535,23 +620,23 @@ static void usb_tick(void) | |||
535 | } | 620 | } |
536 | #endif /* USB_FIREWIRE_HANDLING */ | 621 | #endif /* USB_FIREWIRE_HANDLING */ |
537 | 622 | ||
538 | current_status = usb_detect(); | 623 | int current_status = usb_detect(); |
539 | 624 | ||
540 | /* Only report when the status has changed */ | 625 | /* Only report when the status has changed */ |
541 | if(current_status != last_usb_status) | 626 | if(current_status != last_usb_status) |
542 | { | 627 | { |
543 | last_usb_status = current_status; | 628 | last_usb_status = current_status; |
544 | countdown = NUM_POLL_READINGS; | 629 | usb_countdown = NUM_POLL_READINGS; |
545 | } | 630 | } |
546 | else | 631 | else |
547 | { | 632 | { |
548 | /* Count down until it gets negative */ | 633 | /* Count down until it gets negative */ |
549 | if(countdown >= 0) | 634 | if(usb_countdown >= 0) |
550 | countdown--; | 635 | usb_countdown--; |
551 | 636 | ||
552 | /* Report to the thread if we have had 3 identical status | 637 | /* Report to the thread if we have had 3 identical status |
553 | readings in a row */ | 638 | readings in a row */ |
554 | if(countdown == 0) | 639 | if(usb_countdown == 0) |
555 | { | 640 | { |
556 | queue_post(&usb_queue, current_status, 0); | 641 | queue_post(&usb_queue, current_status, 0); |
557 | } | 642 | } |
@@ -561,7 +646,7 @@ static void usb_tick(void) | |||
561 | if(usb_mmc_countdown > 0) | 646 | if(usb_mmc_countdown > 0) |
562 | { | 647 | { |
563 | usb_mmc_countdown--; | 648 | usb_mmc_countdown--; |
564 | if (usb_mmc_countdown == 0) | 649 | if(usb_mmc_countdown == 0) |
565 | queue_post(&usb_queue, USB_REENABLE, 0); | 650 | queue_post(&usb_queue, USB_REENABLE, 0); |
566 | } | 651 | } |
567 | #endif | 652 | #endif |
@@ -581,25 +666,8 @@ void usb_acknowledge(long id) | |||
581 | 666 | ||
582 | void usb_init(void) | 667 | void usb_init(void) |
583 | { | 668 | { |
584 | /* We assume that the USB cable is extracted */ | ||
585 | usb_state = USB_EXTRACTED; | ||
586 | #if defined(USB_DETECT_BY_DRV) || defined(USB_DETECT_BY_CORE) | ||
587 | last_usb_status = USB_UNPOWERED; | ||
588 | #else | ||
589 | last_usb_status = USB_EXTRACTED; | ||
590 | #endif | ||
591 | usb_monitor_enabled = false; | ||
592 | |||
593 | #ifdef HAVE_USBSTACK | ||
594 | exclusive_storage_access = false; | ||
595 | #endif | ||
596 | |||
597 | #ifdef USB_FIREWIRE_HANDLING | ||
598 | firewire_countdown = -1; | ||
599 | last_firewire_status = false; | ||
600 | #endif | ||
601 | |||
602 | usb_init_device(); | 669 | usb_init_device(); |
670 | |||
603 | #ifdef USB_FULL_INIT | 671 | #ifdef USB_FULL_INIT |
604 | usb_enable(false); | 672 | usb_enable(false); |
605 | 673 | ||
@@ -610,7 +678,6 @@ void usb_init(void) | |||
610 | IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU)); | 678 | IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU)); |
611 | 679 | ||
612 | #ifndef USB_STATUS_BY_EVENT | 680 | #ifndef USB_STATUS_BY_EVENT |
613 | countdown = -1; | ||
614 | tick_add_task(usb_tick); | 681 | tick_add_task(usb_tick); |
615 | #endif | 682 | #endif |
616 | #endif /* USB_FULL_INIT */ | 683 | #endif /* USB_FULL_INIT */ |
@@ -626,14 +693,10 @@ void usb_wait_for_disconnect(struct event_queue *q) | |||
626 | { | 693 | { |
627 | queue_wait(q, &ev); | 694 | queue_wait(q, &ev); |
628 | if(ev.id == SYS_USB_DISCONNECTED) | 695 | if(ev.id == SYS_USB_DISCONNECTED) |
629 | { | ||
630 | usb_acknowledge(SYS_USB_DISCONNECTED_ACK); | ||
631 | return; | 696 | return; |
632 | } | ||
633 | } | 697 | } |
634 | #else | ||
635 | (void)q; | ||
636 | #endif /* USB_FULL_INIT */ | 698 | #endif /* USB_FULL_INIT */ |
699 | (void)q; | ||
637 | } | 700 | } |
638 | 701 | ||
639 | int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks) | 702 | int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks) |
@@ -648,16 +711,14 @@ int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks) | |||
648 | switch(ev.id) | 711 | switch(ev.id) |
649 | { | 712 | { |
650 | case SYS_USB_DISCONNECTED: | 713 | case SYS_USB_DISCONNECTED: |
651 | usb_acknowledge(SYS_USB_DISCONNECTED_ACK); | ||
652 | return 0; | 714 | return 0; |
653 | case SYS_TIMEOUT: | 715 | case SYS_TIMEOUT: |
654 | return 1; | 716 | return 1; |
655 | } | 717 | } |
656 | } | 718 | } |
657 | #else | 719 | #endif /* USB_FULL_INIT */ |
658 | (void)q; (void)ticks; | 720 | (void)q; (void)ticks; |
659 | return 0; | 721 | return 0; |
660 | #endif /* USB_FULL_INIT */ | ||
661 | } | 722 | } |
662 | 723 | ||
663 | #ifdef USB_DRIVER_CLOSE | 724 | #ifdef USB_DRIVER_CLOSE |
@@ -666,7 +727,7 @@ void usb_close(void) | |||
666 | unsigned int thread = usb_thread_entry; | 727 | unsigned int thread = usb_thread_entry; |
667 | usb_thread_entry = 0; | 728 | usb_thread_entry = 0; |
668 | 729 | ||
669 | if (thread == 0) | 730 | if(thread == 0) |
670 | return; | 731 | return; |
671 | 732 | ||
672 | #ifndef USB_STATUS_BY_EVENT | 733 | #ifndef USB_STATUS_BY_EVENT |
@@ -681,11 +742,7 @@ void usb_close(void) | |||
681 | 742 | ||
682 | bool usb_inserted(void) | 743 | bool usb_inserted(void) |
683 | { | 744 | { |
684 | #ifdef HAVE_USB_POWER | ||
685 | return usb_state == USB_INSERTED || usb_state == USB_POWERED; | 745 | return usb_state == USB_INSERTED || usb_state == USB_POWERED; |
686 | #else | ||
687 | return usb_state == USB_INSERTED; | ||
688 | #endif | ||
689 | } | 746 | } |
690 | 747 | ||
691 | #ifdef HAVE_USBSTACK | 748 | #ifdef HAVE_USBSTACK |
@@ -693,20 +750,16 @@ bool usb_exclusive_storage(void) | |||
693 | { | 750 | { |
694 | return exclusive_storage_access; | 751 | return exclusive_storage_access; |
695 | } | 752 | } |
696 | #endif | 753 | #endif /* HAVE_USBSTACK */ |
697 | 754 | ||
698 | int usb_release_exclusive_storage(void) | 755 | int usb_release_exclusive_storage(void) |
699 | { | 756 | { |
700 | int num_acks_to_expect; | 757 | int bccount; |
701 | #ifdef HAVE_USBSTACK | ||
702 | exclusive_storage_access = false; | 758 | exclusive_storage_access = false; |
703 | #endif /* HAVE_USBSTACK */ | ||
704 | /* Tell all threads that we are back in business */ | 759 | /* Tell all threads that we are back in business */ |
705 | num_acks_to_expect = | 760 | bccount = queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1; |
706 | queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1; | 761 | DEBUGF("USB extracted. Broadcast to %d threads...\n", bccount); |
707 | DEBUGF("USB extracted. Waiting for ack from %d threads...\n", | 762 | return bccount; |
708 | num_acks_to_expect); | ||
709 | return num_acks_to_expect; | ||
710 | } | 763 | } |
711 | 764 | ||
712 | #ifdef HAVE_USB_POWER | 765 | #ifdef HAVE_USB_POWER |
@@ -714,7 +767,7 @@ bool usb_powered(void) | |||
714 | { | 767 | { |
715 | return usb_state == USB_POWERED; | 768 | return usb_state == USB_POWERED; |
716 | } | 769 | } |
717 | #endif | 770 | #endif /* HAVE_USB_POWER */ |
718 | 771 | ||
719 | #ifdef USB_ENABLE_HID | 772 | #ifdef USB_ENABLE_HID |
720 | void usb_set_hid(bool enable) | 773 | void usb_set_hid(bool enable) |
@@ -722,16 +775,16 @@ void usb_set_hid(bool enable) | |||
722 | usb_hid = enable; | 775 | usb_hid = enable; |
723 | usb_core_enable_driver(USB_DRIVER_HID, usb_hid); | 776 | usb_core_enable_driver(USB_DRIVER_HID, usb_hid); |
724 | } | 777 | } |
725 | #endif | 778 | #endif /* USB_ENABLE_HID */ |
726 | 779 | ||
727 | #else | 780 | #else /* SIMULATOR || USB_NONE */ |
728 | 781 | ||
729 | #ifdef USB_NONE | 782 | #ifdef USB_NONE |
730 | bool usb_inserted(void) | 783 | bool usb_inserted(void) |
731 | { | 784 | { |
732 | return false; | 785 | return false; |
733 | } | 786 | } |
734 | #endif | 787 | #endif /* USB_NONE */ |
735 | 788 | ||
736 | /* Dummy simulator functions */ | 789 | /* Dummy simulator functions */ |
737 | void usb_acknowledge(long id) | 790 | void usb_acknowledge(long id) |
@@ -757,4 +810,4 @@ void usb_wait_for_disconnect(struct event_queue *q) | |||
757 | (void)q; | 810 | (void)q; |
758 | } | 811 | } |
759 | 812 | ||
760 | #endif /* USB_NONE or SIMULATOR */ | 813 | #endif /* !USB_NONE && !SIMULATOR */ |