diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/ata.c | 95 | ||||
-rw-r--r-- | firmware/drivers/ata.h | 2 |
2 files changed, 63 insertions, 34 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 963929deb7..3fdc93669e 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -19,11 +19,13 @@ | |||
19 | #include <stdbool.h> | 19 | #include <stdbool.h> |
20 | #include "ata.h" | 20 | #include "ata.h" |
21 | #include "kernel.h" | 21 | #include "kernel.h" |
22 | #include "thread.h" | ||
22 | #include "led.h" | 23 | #include "led.h" |
23 | #include "sh7034.h" | 24 | #include "sh7034.h" |
24 | #include "system.h" | 25 | #include "system.h" |
25 | #include "debug.h" | 26 | #include "debug.h" |
26 | #include "panic.h" | 27 | #include "panic.h" |
28 | #include "usb.h" | ||
27 | 29 | ||
28 | #define SECTOR_SIZE 512 | 30 | #define SECTOR_SIZE 512 |
29 | #define ATA_DATA (*((volatile unsigned short*)0x06104100)) | 31 | #define ATA_DATA (*((volatile unsigned short*)0x06104100)) |
@@ -61,6 +63,8 @@ | |||
61 | #define CMD_SLEEP 0xE6 | 63 | #define CMD_SLEEP 0xE6 |
62 | #define CMD_SECURITY_FREEZE_LOCK 0xF5 | 64 | #define CMD_SECURITY_FREEZE_LOCK 0xF5 |
63 | 65 | ||
66 | #define Q_SLEEP 0 | ||
67 | |||
64 | static struct mutex ata_mtx; | 68 | static struct mutex ata_mtx; |
65 | char ata_device; /* device 0 (master) or 1 (slave) */ | 69 | char ata_device; /* device 0 (master) or 1 (slave) */ |
66 | int ata_io_address; /* 0x300 or 0x200, only valid on recorder */ | 70 | int ata_io_address; /* 0x300 or 0x200, only valid on recorder */ |
@@ -68,6 +72,12 @@ static volatile unsigned char* ata_control; | |||
68 | 72 | ||
69 | bool old_recorder = false; | 73 | bool old_recorder = false; |
70 | static bool sleeping = false; | 74 | static bool sleeping = false; |
75 | static int sleep_timer = 0; | ||
76 | static int sleep_timeout = 5*HZ; | ||
77 | static char ata_stack[DEFAULT_STACK_SIZE]; | ||
78 | static char ata_thread_name[] = "ata"; | ||
79 | static struct event_queue ata_queue; | ||
80 | static bool initialized = false; | ||
71 | 81 | ||
72 | static int wait_for_bsy(void) | 82 | static int wait_for_bsy(void) |
73 | { | 83 | { |
@@ -121,7 +131,8 @@ int ata_read_sectors(unsigned long start, | |||
121 | } | 131 | } |
122 | 132 | ||
123 | mutex_lock(&ata_mtx); | 133 | mutex_lock(&ata_mtx); |
124 | 134 | sleep_timer = sleep_timeout; | |
135 | |||
125 | if (!wait_for_rdy()) | 136 | if (!wait_for_rdy()) |
126 | { | 137 | { |
127 | mutex_unlock(&ata_mtx); | 138 | mutex_unlock(&ata_mtx); |
@@ -179,6 +190,7 @@ int ata_write_sectors(unsigned long start, | |||
179 | } | 190 | } |
180 | 191 | ||
181 | mutex_lock(&ata_mtx); | 192 | mutex_lock(&ata_mtx); |
193 | sleep_timer = sleep_timeout; | ||
182 | 194 | ||
183 | if (!wait_for_rdy()) | 195 | if (!wait_for_rdy()) |
184 | { | 196 | { |
@@ -254,58 +266,70 @@ static int freeze_lock(void) | |||
254 | return 0; | 266 | return 0; |
255 | } | 267 | } |
256 | 268 | ||
257 | int ata_spindown(int time) | 269 | void ata_spindown(int seconds) |
270 | { | ||
271 | sleep_timeout = seconds * HZ; | ||
272 | } | ||
273 | |||
274 | static int ata_perform_sleep(void) | ||
258 | { | 275 | { |
259 | int ret = 0; | 276 | int ret = 0; |
260 | 277 | ||
261 | mutex_lock(&ata_mtx); | 278 | mutex_lock(&ata_mtx); |
262 | 279 | ||
263 | if(!wait_for_rdy()) | 280 | if(!wait_for_rdy()) { |
264 | { | ||
265 | mutex_unlock(&ata_mtx); | 281 | mutex_unlock(&ata_mtx); |
266 | return -1; | 282 | return -1; |
267 | } | 283 | } |
268 | 284 | ||
269 | if ( time == -1 ) { | 285 | ATA_SELECT = ata_device; |
270 | ATA_COMMAND = CMD_STANDBY_IMMEDIATE; | 286 | ATA_COMMAND = CMD_SLEEP; |
271 | } | ||
272 | else { | ||
273 | if (time > 255) | ||
274 | { | ||
275 | mutex_unlock(&ata_mtx); | ||
276 | return -1; | ||
277 | } | ||
278 | ATA_NSECTOR = time & 0xff; | ||
279 | ATA_COMMAND = CMD_STANDBY; | ||
280 | } | ||
281 | 287 | ||
282 | if (!wait_for_rdy()) | 288 | if (!wait_for_rdy()) |
283 | ret = -1; | 289 | ret = -1; |
284 | 290 | ||
291 | sleeping = true; | ||
292 | sleep_timer = 0; | ||
285 | mutex_unlock(&ata_mtx); | 293 | mutex_unlock(&ata_mtx); |
286 | return ret; | 294 | return ret; |
287 | } | 295 | } |
288 | 296 | ||
289 | int ata_sleep(void) | 297 | int ata_sleep(void) |
290 | { | 298 | { |
291 | int ret = 0; | 299 | queue_post(&ata_queue, Q_SLEEP, NULL); |
300 | return 0; | ||
301 | } | ||
292 | 302 | ||
293 | mutex_lock(&ata_mtx); | 303 | static void ata_thread(void) |
304 | { | ||
305 | struct event ev; | ||
294 | 306 | ||
295 | if(!wait_for_rdy()) { | 307 | while (1) { |
296 | mutex_unlock(&ata_mtx); | 308 | queue_wait(&ata_queue, &ev); |
297 | return -1; | 309 | switch ( ev.id ) { |
310 | case SYS_USB_CONNECTED: | ||
311 | /* Tell the USB thread that we are safe */ | ||
312 | DEBUGF("backlight_thread got SYS_USB_CONNECTED\n"); | ||
313 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
314 | |||
315 | /* Wait until the USB cable is extracted again */ | ||
316 | usb_wait_for_disconnect(&ata_queue); | ||
317 | break; | ||
318 | |||
319 | case Q_SLEEP: | ||
320 | ata_perform_sleep(); | ||
321 | break; | ||
322 | } | ||
298 | } | 323 | } |
324 | } | ||
299 | 325 | ||
300 | ATA_SELECT = ata_device; | 326 | static void ata_tick(void) |
301 | ATA_COMMAND = CMD_SLEEP; | 327 | { |
302 | 328 | if (sleep_timer) { | |
303 | if (!wait_for_rdy()) | 329 | sleep_timer--; |
304 | ret = -1; | 330 | if (!sleep_timer) |
305 | 331 | queue_post(&ata_queue, 0, NULL); | |
306 | sleeping = true; | 332 | } |
307 | mutex_unlock(&ata_mtx); | ||
308 | return ret; | ||
309 | } | 333 | } |
310 | 334 | ||
311 | int ata_hard_reset(void) | 335 | int ata_hard_reset(void) |
@@ -433,7 +457,7 @@ void ata_enable(bool on) | |||
433 | int ata_init(void) | 457 | int ata_init(void) |
434 | { | 458 | { |
435 | mutex_init(&ata_mtx); | 459 | mutex_init(&ata_mtx); |
436 | 460 | ||
437 | led(false); | 461 | led(false); |
438 | 462 | ||
439 | ata_enable(true); | 463 | ata_enable(true); |
@@ -450,8 +474,13 @@ int ata_init(void) | |||
450 | if (freeze_lock()) | 474 | if (freeze_lock()) |
451 | return -4; | 475 | return -4; |
452 | 476 | ||
453 | if (ata_spindown(1)) | 477 | if ( !initialized ) { |
454 | return -5; | 478 | queue_init(&ata_queue); |
479 | create_thread(ata_thread, ata_stack, | ||
480 | sizeof(ata_stack), ata_thread_name); | ||
481 | tick_add_task(ata_tick); | ||
482 | initialized = true; | ||
483 | } | ||
455 | 484 | ||
456 | ATA_SELECT = SELECT_LBA; | 485 | ATA_SELECT = SELECT_LBA; |
457 | ATA_CONTROL = CONTROL_nIEN; | 486 | ATA_CONTROL = CONTROL_nIEN; |
diff --git a/firmware/drivers/ata.h b/firmware/drivers/ata.h index 23dd1fac58..77c4c2b7bf 100644 --- a/firmware/drivers/ata.h +++ b/firmware/drivers/ata.h | |||
@@ -33,7 +33,7 @@ | |||
33 | 255 21 min 15 s | 33 | 255 21 min 15 s |
34 | */ | 34 | */ |
35 | extern void ata_enable(bool on); | 35 | extern void ata_enable(bool on); |
36 | extern int ata_spindown(int time); | 36 | extern void ata_spindown(int seconds); |
37 | extern int ata_sleep(void); | 37 | extern int ata_sleep(void); |
38 | extern int ata_hard_reset(void); | 38 | extern int ata_hard_reset(void); |
39 | extern int ata_soft_reset(void); | 39 | extern int ata_soft_reset(void); |