diff options
Diffstat (limited to 'firmware/usb.c')
-rw-r--r-- | firmware/usb.c | 146 |
1 files changed, 134 insertions, 12 deletions
diff --git a/firmware/usb.c b/firmware/usb.c index a3421c7d47..c6ae306218 100644 --- a/firmware/usb.c +++ b/firmware/usb.c | |||
@@ -22,6 +22,14 @@ | |||
22 | #include "thread.h" | 22 | #include "thread.h" |
23 | #include "system.h" | 23 | #include "system.h" |
24 | #include "debug.h" | 24 | #include "debug.h" |
25 | #include "ata.h" | ||
26 | #include "fat.h" | ||
27 | #include "disk.h" | ||
28 | #include "panic.h" | ||
29 | |||
30 | |||
31 | #define USB_REALLY_BRAVE | ||
32 | |||
25 | 33 | ||
26 | #ifndef SIMULATOR | 34 | #ifndef SIMULATOR |
27 | 35 | ||
@@ -30,7 +38,55 @@ | |||
30 | 38 | ||
31 | static char usb_stack[0x100]; | 39 | static char usb_stack[0x100]; |
32 | static struct event_queue usb_queue; | 40 | static struct event_queue usb_queue; |
33 | static bool usb_connected; | 41 | static bool last_usb_status; |
42 | static bool usb_monitor_enabled; | ||
43 | |||
44 | static void usb_enable(bool on) | ||
45 | { | ||
46 | #ifdef ARCHOS_RECORDER | ||
47 | if(!on) /* The pin is inverted on the Recorder */ | ||
48 | #else | ||
49 | if(on) | ||
50 | #endif | ||
51 | PADR &= ~0x400; /* enable USB */ | ||
52 | else | ||
53 | PADR |= 0x400; | ||
54 | PAIOR |= 0x400; | ||
55 | } | ||
56 | |||
57 | static void usb_slave_mode(bool on) | ||
58 | { | ||
59 | int rc; | ||
60 | struct partinfo* pinfo; | ||
61 | |||
62 | if(on) | ||
63 | { | ||
64 | DEBUGF("Entering USB slave mode\n"); | ||
65 | ata_enable(false); | ||
66 | usb_enable(true); | ||
67 | } | ||
68 | else | ||
69 | { | ||
70 | DEBUGF("Leaving USB slave mode\n"); | ||
71 | |||
72 | /* Let the ISDx00 settle */ | ||
73 | sleep(HZ*1); | ||
74 | |||
75 | usb_enable(false); | ||
76 | |||
77 | rc = ata_init(); | ||
78 | if(rc) | ||
79 | panicf("ata: %d",rc); | ||
80 | |||
81 | pinfo = disk_init(); | ||
82 | if (!pinfo) | ||
83 | panicf("disk: NULL"); | ||
84 | |||
85 | rc = fat_mount(pinfo[0].start); | ||
86 | if(rc) | ||
87 | panicf("mount: %d",rc); | ||
88 | } | ||
89 | } | ||
34 | 90 | ||
35 | static void usb_thread(void) | 91 | static void usb_thread(void) |
36 | { | 92 | { |
@@ -50,7 +106,8 @@ static void usb_thread(void) | |||
50 | We subtract one for our own thread. */ | 106 | We subtract one for our own thread. */ |
51 | num_acks_to_expect = queue_broadcast(SYS_USB_CONNECTED, NULL) - 1; | 107 | num_acks_to_expect = queue_broadcast(SYS_USB_CONNECTED, NULL) - 1; |
52 | waiting_for_ack = true; | 108 | waiting_for_ack = true; |
53 | DEBUGF("USB inserted. Waiting for ack from %d threads...\n"); | 109 | DEBUGF("USB inserted. Waiting for ack from %d threads...\n", |
110 | num_acks_to_expect); | ||
54 | break; | 111 | break; |
55 | 112 | ||
56 | case SYS_USB_CONNECTED_ACK: | 113 | case SYS_USB_CONNECTED_ACK: |
@@ -65,13 +122,43 @@ static void usb_thread(void) | |||
65 | current firmware isn't quite ready for this yet. | 122 | current firmware isn't quite ready for this yet. |
66 | Let's just chicken out and reboot. */ | 123 | Let's just chicken out and reboot. */ |
67 | DEBUGF("All threads have acknowledged. Rebooting...\n"); | 124 | DEBUGF("All threads have acknowledged. Rebooting...\n"); |
125 | #ifdef USB_REALLY_BRAVE | ||
126 | usb_slave_mode(true); | ||
127 | #else | ||
68 | system_reboot(); | 128 | system_reboot(); |
129 | #endif | ||
69 | } | 130 | } |
70 | else | 131 | else |
71 | { | 132 | { |
72 | DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect); | 133 | DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect); |
73 | } | 134 | } |
74 | } | 135 | } |
136 | break; | ||
137 | |||
138 | case USB_EXTRACTED: | ||
139 | /* Tell all threads that we are back in business */ | ||
140 | num_acks_to_expect = | ||
141 | queue_broadcast(SYS_USB_DISCONNECTED, NULL) - 1; | ||
142 | waiting_for_ack = true; | ||
143 | DEBUGF("USB extracted. Waiting for ack from %d threads...\n", | ||
144 | num_acks_to_expect); | ||
145 | break; | ||
146 | |||
147 | case SYS_USB_DISCONNECTED_ACK: | ||
148 | if(waiting_for_ack) | ||
149 | { | ||
150 | num_acks_to_expect--; | ||
151 | if(num_acks_to_expect == 0) | ||
152 | { | ||
153 | DEBUGF("All threads have acknowledged. We're in business.\n"); | ||
154 | usb_slave_mode(false); | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect); | ||
159 | } | ||
160 | } | ||
161 | break; | ||
75 | } | 162 | } |
76 | } | 163 | } |
77 | } | 164 | } |
@@ -80,16 +167,23 @@ static void usb_tick(void) | |||
80 | { | 167 | { |
81 | bool current_status; | 168 | bool current_status; |
82 | 169 | ||
170 | if(usb_monitor_enabled) | ||
171 | { | ||
83 | #ifdef ARCHOS_RECORDER | 172 | #ifdef ARCHOS_RECORDER |
84 | current_status = (PCDR & 0x04)?true:false; | 173 | current_status = (PCDR & 0x04)?true:false; |
85 | #else | 174 | #else |
86 | current_status = (PADR & 0x8000)?false:true; | 175 | current_status = (PADR & 0x8000)?false:true; |
87 | #endif | 176 | #endif |
88 | 177 | ||
89 | if(current_status && !usb_connected) | 178 | /* Only report when the status has changed */ |
90 | { | 179 | if(current_status != last_usb_status) |
91 | usb_connected = true; | 180 | { |
92 | queue_post(&usb_queue, USB_INSERTED, NULL); | 181 | last_usb_status = current_status; |
182 | if(current_status) | ||
183 | queue_post(&usb_queue, USB_INSERTED, NULL); | ||
184 | else | ||
185 | queue_post(&usb_queue, USB_EXTRACTED, NULL); | ||
186 | } | ||
93 | } | 187 | } |
94 | } | 188 | } |
95 | 189 | ||
@@ -100,14 +194,38 @@ void usb_acknowledge(int id) | |||
100 | 194 | ||
101 | void usb_init(void) | 195 | void usb_init(void) |
102 | { | 196 | { |
103 | int rc; | 197 | usb_monitor_enabled = false; |
104 | 198 | ||
105 | usb_connected = false; | 199 | usb_enable(false); |
200 | |||
201 | /* We assume that the USB cable is extracted */ | ||
202 | last_usb_status = false; | ||
106 | 203 | ||
107 | queue_init(&usb_queue); | 204 | queue_init(&usb_queue); |
108 | create_thread(usb_thread, usb_stack, sizeof(usb_stack)); | 205 | create_thread(usb_thread, usb_stack, sizeof(usb_stack)); |
109 | 206 | ||
110 | rc = tick_add_task(usb_tick); | 207 | tick_add_task(usb_tick); |
208 | } | ||
209 | |||
210 | void usb_wait_for_disconnect(struct event_queue *q) | ||
211 | { | ||
212 | struct event ev; | ||
213 | |||
214 | /* Don't return until we get SYS_USB_DISCONNECTED */ | ||
215 | while(1) | ||
216 | { | ||
217 | queue_wait(q, &ev); | ||
218 | if(ev.id == SYS_USB_DISCONNECTED) | ||
219 | { | ||
220 | usb_acknowledge(SYS_USB_DISCONNECTED_ACK); | ||
221 | return; | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | |||
226 | void usb_start_monitoring(void) | ||
227 | { | ||
228 | usb_monitor_enabled = true; | ||
111 | } | 229 | } |
112 | 230 | ||
113 | #else | 231 | #else |
@@ -122,4 +240,8 @@ void usb_init(void) | |||
122 | { | 240 | { |
123 | } | 241 | } |
124 | 242 | ||
243 | void usb_start_monitoring(void) | ||
244 | { | ||
245 | } | ||
246 | |||
125 | #endif | 247 | #endif |