summaryrefslogtreecommitdiff
path: root/firmware/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/usb.c')
-rw-r--r--firmware/usb.c357
1 files changed, 164 insertions, 193 deletions
diff --git a/firmware/usb.c b/firmware/usb.c
index ec47e0653c..b52a255c0a 100644
--- a/firmware/usb.c
+++ b/firmware/usb.c
@@ -79,7 +79,7 @@ static int usb_mmc_countdown = 0;
79static long usb_stack[(DEFAULT_STACK_SIZE + 0x800)/sizeof(long)]; 79static long usb_stack[(DEFAULT_STACK_SIZE + 0x800)/sizeof(long)];
80static const char usb_thread_name[] = "usb"; 80static const char usb_thread_name[] = "usb";
81static unsigned int usb_thread_entry = 0; 81static unsigned int usb_thread_entry = 0;
82#endif 82#endif /* USB_FULL_INIT */
83static struct event_queue usb_queue; 83static struct event_queue usb_queue;
84static int last_usb_status; 84static int last_usb_status;
85static bool usb_monitor_enabled; 85static bool usb_monitor_enabled;
@@ -87,16 +87,80 @@ static bool usb_monitor_enabled;
87static bool exclusive_storage_access; 87static bool exclusive_storage_access;
88#endif 88#endif
89 89
90 90#ifdef USB_FIREWIRE_HANDLING
91#if defined(IPOD_COLOR) || defined(IPOD_4G) \
92 || defined(IPOD_MINI) || defined(IPOD_MINI2G)
93static int firewire_countdown; 91static int firewire_countdown;
94static bool last_firewire_status; 92static bool last_firewire_status;
95#endif 93#endif
96 94
97#ifdef USB_FULL_INIT 95#ifdef USB_FULL_INIT
98#ifndef HAVE_USBSTACK 96
99static void usb_slave_mode(bool on) 97#if defined(USB_FIREWIRE_HANDLING) \
98 || (defined(HAVE_USBSTACK) && !defined(USE_ROCKBOX_USB))
99static void try_reboot(void)
100{
101#ifdef HAVE_DISK_STORAGE
102 storage_sleepnow(); /* Immediately spindown the disk. */
103 sleep(HZ*2);
104#endif
105
106#ifdef IPOD_ARCH /* The following code is based on ipodlinux */
107#if CONFIG_CPU == PP5020
108 memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21);
109#elif CONFIG_CPU == PP5022
110 memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21);
111#endif /* CONFIG_CPU */
112#endif /* IPOD_ARCH */
113
114 system_reboot(); /* Reboot */
115}
116#endif /* USB_FIRWIRE_HANDLING || (HAVE_USBSTACK && !USE_ROCKBOX_USB) */
117
118#ifdef HAVE_USBSTACK
119/* inline since branch is chosen at compile time */
120static inline void usb_slave_mode(bool on)
121{
122#ifdef USE_ROCKBOX_USB
123 int rc;
124
125 if (on)
126 {
127 trigger_cpu_boost();
128#ifdef HAVE_PRIORITY_SCHEDULING
129 thread_set_priority(THREAD_ID_CURRENT, PRIORITY_REALTIME);
130#endif
131 usb_enable(true);
132 }
133 else /* usb_state == USB_INSERTED (only!) */
134 {
135 usb_enable(false);
136#ifdef HAVE_PRIORITY_SCHEDULING
137 thread_set_priority(THREAD_ID_CURRENT, PRIORITY_SYSTEM);
138#endif
139 /* Entered exclusive mode */
140 rc = disk_mount_all();
141 if (rc <= 0) /* no partition */
142 panicf("mount: %d",rc);
143
144 cancel_cpu_boost();
145 }
146#else /* !USB_ROCKBOX_USB */
147 if (on)
148 {
149 /* until we have native mass-storage mode, we want to reboot on
150 usb host connect */
151 try_reboot();
152 }
153#endif /* USE_ROCKBOX_USB */
154}
155
156void usb_signal_transfer_completion(
157 struct usb_transfer_completion_event_data* event_data)
158{
159 queue_post(&usb_queue, USB_TRANSFER_COMPLETION, (intptr_t)event_data);
160}
161#else /* !HAVE_USBSTACK */
162/* inline since branch is chosen at compile time */
163static inline void usb_slave_mode(bool on)
100{ 164{
101 int rc; 165 int rc;
102 166
@@ -107,11 +171,14 @@ static void usb_slave_mode(bool on)
107 storage_init(); 171 storage_init();
108 storage_enable(false); 172 storage_enable(false);
109 usb_enable(true); 173 usb_enable(true);
174 cpu_idle_mode(true);
110 } 175 }
111 else 176 else
112 { 177 {
113 DEBUGF("Leaving USB slave mode\n"); 178 DEBUGF("Leaving USB slave mode\n");
114 179
180 cpu_idle_mode(false);
181
115 /* Let the ISDx00 settle */ 182 /* Let the ISDx00 settle */
116 sleep(HZ*1); 183 sleep(HZ*1);
117 184
@@ -126,34 +193,31 @@ static void usb_slave_mode(bool on)
126 panicf("mount: %d",rc); 193 panicf("mount: %d",rc);
127 } 194 }
128} 195}
129#endif 196#endif /* HAVE_USBSTACK */
130 197
131static void try_reboot(void) 198#ifdef HAVE_USB_POWER
199static inline bool usb_power_button(void)
132{ 200{
133#ifdef HAVE_DISK_STORAGE 201#if defined(IRIVER_H10) || defined (IRIVER_H10_5GB)
134 storage_sleepnow(); /* Immediately spindown the disk. */ 202 return (button_status() & ~USBPOWER_BTN_IGNORE) != USBPOWER_BUTTON;
135 sleep(HZ*2); 203#else
204 return (button_status() & ~USBPOWER_BTN_IGNORE) == USBPOWER_BUTTON;
136#endif 205#endif
206}
137 207
138#ifdef IPOD_ARCH /* The following code is based on ipodlinux */ 208#ifdef USB_FIREWIRE_HANDLING
139#if CONFIG_CPU == PP5020 209static inline bool usb_reboot_button(void)
140 memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21); 210{
141#elif CONFIG_CPU == PP5022 211 return (button_status() & ~USBPOWER_BTN_IGNORE) != USBPOWER_BUTTON;
142 memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21);
143#endif /* CONFIG_CPU */
144#endif /* IPOD_ARCH */
145
146 system_reboot(); /* Reboot */
147} 212}
213#endif
214#endif /* HAVE_USB_POWER */
148 215
149static void usb_thread(void) 216static void usb_thread(void)
150{ 217{
151 int num_acks_to_expect = -1; 218 int num_acks_to_expect = 0;
152 bool waiting_for_ack;
153 struct queue_event ev; 219 struct queue_event ev;
154 220
155 waiting_for_ack = false;
156
157 while(1) 221 while(1)
158 { 222 {
159 queue_wait(&usb_queue, &ev); 223 queue_wait(&usb_queue, &ev);
@@ -165,180 +229,116 @@ static void usb_thread(void)
165#endif 229#endif
166#ifdef HAVE_USBSTACK 230#ifdef HAVE_USBSTACK
167 case USB_TRANSFER_COMPLETION: 231 case USB_TRANSFER_COMPLETION:
168 usb_core_handle_transfer_completion((struct usb_transfer_completion_event_data*)ev.data); 232 usb_core_handle_transfer_completion(
169 break; 233 (struct usb_transfer_completion_event_data*)ev.data);
170#endif
171#ifdef HAVE_USB_POWER
172 case USB_POWERED:
173 usb_state = USB_POWERED;
174 break; 234 break;
175#endif 235#endif
176 case USB_INSERTED: 236 case USB_INSERTED:
177#ifdef HAVE_LCD_BITMAP 237#ifdef HAVE_LCD_BITMAP
178 if(do_screendump_instead_of_usb) 238 if(do_screendump_instead_of_usb)
179 { 239 {
240 usb_state = USB_SCREENDUMP;
180 screen_dump(); 241 screen_dump();
242 break;
181 } 243 }
182 else
183#endif 244#endif
184#ifdef HAVE_USB_POWER 245#ifdef HAVE_USB_POWER
185#if defined(IRIVER_H10) || defined (IRIVER_H10_5GB) 246 if (usb_power_button())
186 if((button_status() & ~USBPOWER_BTN_IGNORE) != USBPOWER_BUTTON)
187#else
188 if((button_status() & ~USBPOWER_BTN_IGNORE) == USBPOWER_BUTTON)
189#endif
190 { 247 {
248 /* Only charging is desired */
191 usb_state = USB_POWERED; 249 usb_state = USB_POWERED;
192#ifdef HAVE_USBSTACK 250#ifdef HAVE_USBSTACK
193 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE,false); 251 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, false);
194 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY,true); 252 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true);
195 usb_enable(true);
196#endif
197 }
198 else
199#endif
200 {
201#ifdef HAVE_USBSTACK
202 /* Set the state to USB_POWERED for now. if a real
203 connection is detected it will switch to USB_INSERTED */
204 usb_state = USB_POWERED;
205 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE,true);
206 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY,false);
207 usb_enable(true); 253 usb_enable(true);
208#else
209 /* Tell all threads that they have to back off the ATA.
210 We subtract one for our own thread. */
211 num_acks_to_expect =
212 queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
213 waiting_for_ack = true;
214 DEBUGF("USB inserted. Waiting for ack from %d threads...\n",
215 num_acks_to_expect);
216#endif 254#endif
255 break;
217 } 256 }
218 break; 257#endif /* HAVE_USB_POWER */
219#ifdef HAVE_USBSTACK 258#ifdef HAVE_USBSTACK
220 case USB_REQUEST_DISK: 259 /* Set the state to USB_POWERED for now. If permission to connect
221 if(!waiting_for_ack) 260 * by threads and storage is granted it will be changed to
261 * USB_CONNECTED. */
262 usb_state = USB_POWERED;
263 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, true);
264 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false);
265
266 /* Check any drivers enabled at this point for exclusive storage
267 * access requirements. */
268 exclusive_storage_access = usb_core_any_exclusive_storage();
269
270 if (exclusive_storage_access)
271#endif /* HAVE_USBSTACK */
222 { 272 {
223 /* Tell all threads that they have to back off the ATA. 273 /* Tell all threads that they have to back off the storage.
224 We subtract one for our own thread. */ 274 We subtract one for our own thread. */
225 num_acks_to_expect = 275 num_acks_to_expect = queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
226 queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
227 waiting_for_ack = true;
228 DEBUGF("USB inserted. Waiting for ack from %d threads...\n", 276 DEBUGF("USB inserted. Waiting for ack from %d threads...\n",
229 num_acks_to_expect); 277 num_acks_for_connect);
230 } 278 }
231 break; 279 break;
232 case USB_RELEASE_DISK: 280
233 if(!waiting_for_ack) 281 case SYS_USB_CONNECTED_ACK:
282 if(num_acks_to_expect > 0 && --num_acks_to_expect == 0)
234 { 283 {
235 /* Tell all threads that they have to back off the ATA. 284 DEBUGF("All threads have acknowledged the connect.\n");
236 We subtract one for our own thread. */ 285 usb_slave_mode(true);
237 num_acks_to_expect = 286 usb_state = USB_INSERTED;
238 queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
239 waiting_for_ack = true;
240 DEBUGF("USB inserted. Waiting for ack from %d threads...\n",
241 num_acks_to_expect);
242 } 287 }
243 break; 288 else
244#endif
245 case SYS_USB_CONNECTED_ACK:
246 if(waiting_for_ack)
247 { 289 {
248 num_acks_to_expect--; 290 DEBUGF("usb: got ack, %d to go...\n",
249 if(num_acks_to_expect == 0) 291 num_acks_to_expect);
250 {
251 DEBUGF("All threads have acknowledged the connect.\n");
252#ifdef HAVE_USBSTACK
253#ifndef USE_ROCKBOX_USB
254 /* until we have native mass-storage mode, we want to reboot on
255 usb host connect */
256 try_reboot();
257#endif /* USE_ROCKBOX_USB */
258#ifdef HAVE_PRIORITY_SCHEDULING
259 thread_set_priority(usb_thread_entry,PRIORITY_REALTIME);
260#endif
261 exclusive_storage_access = true;
262
263#else
264 usb_slave_mode(true);
265 cpu_idle_mode(true);
266#endif
267 usb_state = USB_INSERTED;
268 waiting_for_ack = false;
269 }
270 else
271 {
272 DEBUGF("usb: got ack, %d to go...\n",
273 num_acks_to_expect);
274 }
275 } 292 }
276 break; 293 break;
277 294
278 case USB_EXTRACTED: 295 case USB_EXTRACTED:
279#ifdef HAVE_USBSTACK
280 usb_enable(false);
281#ifdef HAVE_PRIORITY_SCHEDULING
282 thread_set_priority(usb_thread_entry,PRIORITY_SYSTEM);
283#endif
284#endif
285#ifdef HAVE_LCD_BITMAP 296#ifdef HAVE_LCD_BITMAP
286 if(do_screendump_instead_of_usb) 297 if(usb_state == USB_SCREENDUMP)
287 break; 298 {
288#endif 299 usb_state = USB_EXTRACTED;
289#ifdef HAVE_USB_POWER 300 break; /* Connected for screendump only */
301 }
302#endif /* HAVE_LCD_BITMAP */
303#ifndef HAVE_USBSTACK /* Stack must undo this if POWERED state was transitional */
290 if(usb_state == USB_POWERED) 304 if(usb_state == USB_POWERED)
291 { 305 {
292 usb_state = USB_EXTRACTED; 306 usb_state = USB_EXTRACTED;
293 break; 307 break;
294 } 308 }
295#endif 309#endif /* HAVE_USBSTACK */
296#ifndef HAVE_USBSTACK
297 if(usb_state == USB_INSERTED) 310 if(usb_state == USB_INSERTED)
298 { 311 {
299 /* Only disable the USB mode if we really have enabled it 312 /* Only disable the USB mode if we really have enabled it
300 some threads might not have acknowledged the 313 some threads might not have acknowledged the
301 insertion */ 314 insertion */
302 usb_slave_mode(false); 315 usb_slave_mode(false);
303 cpu_idle_mode(false);
304 } 316 }
305#endif
306 317
307 usb_state = USB_EXTRACTED; 318 usb_state = USB_EXTRACTED;
308#ifdef HAVE_USBSTACK 319#ifdef HAVE_USBSTACK
309 if(exclusive_storage_access) 320 if (!exclusive_storage_access)
310 { 321 break;
311 int rc = disk_mount_all(); 322
312 if (rc <= 0) /* no partition */ 323 exclusive_storage_access = false;
313 panicf("mount: %d",rc); 324#endif /* HAVE_USBSTACK */
314 exclusive_storage_access = false; 325 /* Tell all threads that we are back in business */
315#endif 326 num_acks_to_expect =
316 /* Tell all threads that we are back in business */ 327 queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
317 num_acks_to_expect = 328 DEBUGF("USB extracted. Waiting for ack from %d threads...\n",
318 queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1; 329 num_acks_to_expect);
319 waiting_for_ack = true;
320 DEBUGF("USB extracted. Waiting for ack from %d threads...\n",
321 num_acks_to_expect);
322#ifdef HAVE_USBSTACK
323 }
324#endif
325 break; 330 break;
326 331
327 case SYS_USB_DISCONNECTED_ACK: 332 case SYS_USB_DISCONNECTED_ACK:
328 if(waiting_for_ack) 333 if(num_acks_to_expect > 0 && --num_acks_to_expect == 0)
329 { 334 {
330 num_acks_to_expect--; 335 DEBUGF("All threads have acknowledged. "
331 if(num_acks_to_expect == 0) 336 "We're in business.\n");
332 { 337 }
333 DEBUGF("All threads have acknowledged. " 338 else
334 "We're in business.\n"); 339 {
335 waiting_for_ack = false; 340 DEBUGF("usb: got ack, %d to go...\n",
336 } 341 num_acks_to_expect);
337 else
338 {
339 DEBUGF("usb: got ack, %d to go...\n",
340 num_acks_to_expect);
341 }
342 } 342 }
343 break; 343 break;
344 344
@@ -347,49 +347,44 @@ static void usb_thread(void)
347 case SYS_HOTSWAP_EXTRACTED: 347 case SYS_HOTSWAP_EXTRACTED:
348#ifdef HAVE_USBSTACK 348#ifdef HAVE_USBSTACK
349 usb_core_hotswap_event(1,ev.id == SYS_HOTSWAP_INSERTED); 349 usb_core_hotswap_event(1,ev.id == SYS_HOTSWAP_INSERTED);
350#else 350#else /* !HAVE_USBSTACK */
351 if(usb_state == USB_INSERTED) 351 if(usb_state == USB_INSERTED)
352 { 352 {
353 usb_enable(false); 353 usb_enable(false);
354#if (CONFIG_STORAGE & STORAGE_MMC) 354#if (CONFIG_STORAGE & STORAGE_MMC)
355 usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */ 355 usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */
356#endif 356#endif /* STORAGE_MMC */
357 } 357 }
358#endif 358#endif /* HAVE_USBSTACK */
359 break; 359 break;
360 360
361#if (CONFIG_STORAGE & STORAGE_MMC)
361 case USB_REENABLE: 362 case USB_REENABLE:
362 if(usb_state == USB_INSERTED) 363 if(usb_state == USB_INSERTED)
363 usb_enable(true); /* reenable only if still inserted */ 364 usb_enable(true); /* reenable only if still inserted */
364 break; 365 break;
366#endif /* STORAGE_MMC */
365#endif /* HAVE_HOTSWAP */ 367#endif /* HAVE_HOTSWAP */
368
369#ifdef USB_FIREWIRE_HANDLING
366 case USB_REQUEST_REBOOT: 370 case USB_REQUEST_REBOOT:
367#ifdef HAVE_USB_POWER 371#ifdef HAVE_USB_POWER
368 if((button_status() & ~USBPOWER_BTN_IGNORE) != USBPOWER_BUTTON) 372 if (usb_reboot_button())
369#endif 373#endif
370 try_reboot(); 374 try_reboot();
371 break; 375 break;
376#endif /* USB_FIREWIRE_HANDLING */
372 } 377 }
373 } 378 }
374} 379}
375#endif
376 380
377#ifdef HAVE_USBSTACK
378void usb_signal_transfer_completion(struct usb_transfer_completion_event_data* event_data)
379{
380 queue_post(&usb_queue, USB_TRANSFER_COMPLETION, (intptr_t)event_data);
381}
382#endif
383
384#ifdef USB_FULL_INIT
385static void usb_tick(void) 381static void usb_tick(void)
386{ 382{
387 int current_status; 383 int current_status;
388 384
389 if(usb_monitor_enabled) 385 if(usb_monitor_enabled)
390 { 386 {
391#if defined(IPOD_COLOR) || defined(IPOD_4G) \ 387#ifdef USB_FIREWIRE_HANDLING
392 || defined(IPOD_MINI) || defined(IPOD_MINI2G)
393 int current_firewire_status = firewire_detect(); 388 int current_firewire_status = firewire_detect();
394 if(current_firewire_status != last_firewire_status) 389 if(current_firewire_status != last_firewire_status)
395 { 390 {
@@ -409,7 +404,7 @@ static void usb_tick(void)
409 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0); 404 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
410 } 405 }
411 } 406 }
412#endif 407#endif /* USB_FIREWIRE_HANDLING */
413 408
414 current_status = usb_detect(); 409 current_status = usb_detect();
415 410
@@ -442,7 +437,7 @@ static void usb_tick(void)
442 } 437 }
443#endif 438#endif
444} 439}
445#endif 440#endif /* USB_FULL_INIT */
446 441
447void usb_acknowledge(long id) 442void usb_acknowledge(long id)
448{ 443{
@@ -458,8 +453,7 @@ void usb_init(void)
458 usb_monitor_enabled = false; 453 usb_monitor_enabled = false;
459 countdown = -1; 454 countdown = -1;
460 455
461#if defined(IPOD_COLOR) || defined(IPOD_4G) \ 456#ifdef USB_FIREWIRE_HANDLING
462 || defined(IPOD_MINI) || defined(IPOD_MINI2G)
463 firewire_countdown = -1; 457 firewire_countdown = -1;
464 last_firewire_status = false; 458 last_firewire_status = false;
465#endif 459#endif
@@ -480,8 +474,7 @@ void usb_init(void)
480 IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU)); 474 IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU));
481 475
482 tick_add_task(usb_tick); 476 tick_add_task(usb_tick);
483#endif 477#endif /* USB_FULL_INIT */
484
485} 478}
486 479
487void usb_wait_for_disconnect(struct event_queue *q) 480void usb_wait_for_disconnect(struct event_queue *q)
@@ -518,10 +511,8 @@ int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks)
518 case SYS_USB_DISCONNECTED: 511 case SYS_USB_DISCONNECTED:
519 usb_acknowledge(SYS_USB_DISCONNECTED_ACK); 512 usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
520 return 0; 513 return 0;
521 break;
522 case SYS_TIMEOUT: 514 case SYS_TIMEOUT:
523 return 1; 515 return 1;
524 break;
525 } 516 }
526 } 517 }
527#else 518#else
@@ -562,27 +553,7 @@ bool usb_inserted(void)
562} 553}
563 554
564#ifdef HAVE_USBSTACK 555#ifdef HAVE_USBSTACK
565void usb_request_exclusive_ata(void) 556bool usb_exclusive_storage(void)
566{
567 /* This is not really a clean place to start boosting the cpu. but it's
568 * currently the best one. We want to get rid of having to boost the cpu
569 * for usb anyway */
570 trigger_cpu_boost();
571 if(!exclusive_storage_access) {
572 queue_post(&usb_queue, USB_REQUEST_DISK, 0);
573 }
574}
575
576void usb_release_exclusive_ata(void)
577{
578 cancel_cpu_boost();
579 if(exclusive_storage_access) {
580 queue_post(&usb_queue, USB_RELEASE_DISK, 0);
581 exclusive_storage_access = false;
582 }
583}
584
585bool usb_exclusive_ata(void)
586{ 557{
587 return exclusive_storage_access; 558 return exclusive_storage_access;
588} 559}