1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
|
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2009 by Jens Arnold
* Copyright (C) 2011 by Thomas Martitz
*
* Rockbox simulator specific tasks
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "kernel.h"
#include "screendump.h"
#include "thread.h"
#include "debug.h"
#include "usb.h"
#include "mv.h"
#include "ata_idle_notify.h"
#ifdef WIN32
#include <windows.h>
#endif
static void sim_thread(void);
static long sim_thread_stack[DEFAULT_STACK_SIZE/sizeof(long)];
/* stack isn't actually used in the sim */
static const char sim_thread_name[] = "sim";
static struct event_queue sim_queue;
/* possible events for the sim thread */
enum {
SIM_SCREENDUMP,
SIM_USB_INSERTED,
SIM_USB_EXTRACTED,
#ifdef HAVE_MULTIDRIVE
SIM_EXT_INSERTED,
SIM_EXT_EXTRACTED,
#endif
};
#ifdef HAVE_MULTIDRIVE
extern void sim_ext_extracted(int drive);
#endif
void sim_thread(void)
{
struct queue_event ev;
long last_broadcast_tick = current_tick;
int num_acks_to_expect = 0;
while (1)
{
queue_wait_w_tmo(&sim_queue, &ev, 5*HZ);
switch(ev.id)
{
case SYS_TIMEOUT:
call_storage_idle_notifys(false);
break;
case SIM_SCREENDUMP:
screen_dump();
#ifdef HAVE_REMOTE_LCD
remote_screen_dump();
#endif
break;
case SIM_USB_INSERTED:
/* from firmware/usb.c: */
/* Tell all threads that they have to back off the storage.
We subtract one for our own thread. Expect an ACK for every
listener for each broadcast they received. If it has been too
long, the user might have entered a screen that didn't ACK
when inserting the cable, such as a debugging screen. In that
case, reset the count or else USB would be locked out until
rebooting because it most likely won't ever come. Simply
resetting to the most recent broadcast count is racy. */
if(TIME_AFTER(current_tick, last_broadcast_tick + HZ*5))
{
num_acks_to_expect = 0;
last_broadcast_tick = current_tick;
}
/* NOTE: Unlike the USB code, we do not subtract one here
* because the sim_queue is not registered for broadcasts! */
num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0);
DEBUGF("USB inserted. Waiting for %d acks...\n",
num_acks_to_expect);
break;
case SYS_USB_CONNECTED_ACK:
if(num_acks_to_expect > 0 && --num_acks_to_expect == 0)
{
DEBUGF("All threads have acknowledged the connect.\n");
}
else
{
DEBUGF("usb: got ack, %d to go...\n",
num_acks_to_expect);
}
break;
case SIM_USB_EXTRACTED:
/* in usb.c, this is only done for exclusive storage
* do it here anyway but don't depend on the acks */
queue_broadcast(SYS_USB_DISCONNECTED, 0);
break;
#ifdef HAVE_MULTIDRIVE
case SIM_EXT_INSERTED:
case SIM_EXT_EXTRACTED:
sim_ext_extracted(ev.data);
queue_broadcast(ev.id == SIM_EXT_INSERTED ?
SYS_HOTSWAP_INSERTED : SYS_HOTSWAP_EXTRACTED, 0);
sleep(HZ/20);
queue_broadcast(SYS_FS_CHANGED, 0);
break;
#endif /* HAVE_MULTIDRIVE */
default:
DEBUGF("sim_tasks: unhandled event: %ld\n", ev.id);
break;
}
}
}
void sim_tasks_init(void)
{
queue_init(&sim_queue, false);
create_thread(sim_thread, sim_thread_stack, sizeof(sim_thread_stack), 0,
sim_thread_name IF_PRIO(,PRIORITY_BACKGROUND) IF_COP(,CPU));
}
void sim_trigger_screendump(void)
{
queue_post(&sim_queue, SIM_SCREENDUMP, 0);
}
#ifdef HAVE_HEADPHONE_DETECTION
static bool is_hp_inserted = true;
bool headphones_inserted(void)
{
return is_hp_inserted;
}
void sim_trigger_hp(bool inserted)
{
is_hp_inserted = inserted;
DEBUGF("Headphone %s.\n", inserted ? "inserted":"removed");
}
#endif
#ifdef HAVE_LINEOUT_DETECTION
static bool is_lo_inserted = false;
bool lineout_inserted(void)
{
return is_lo_inserted;
}
void sim_trigger_lo(bool inserted)
{
is_lo_inserted = inserted;
DEBUGF("Lineout %s.\n", inserted ? "inserted":"removed");
}
#endif
static bool is_usb_inserted;
void sim_trigger_usb(bool inserted)
{
int usbmode = -1;
if (inserted)
{
send_event(SYS_EVENT_USB_INSERTED, &usbmode);
queue_post(&sim_queue, SIM_USB_INSERTED, 0);
}
else
{
send_event(SYS_EVENT_USB_EXTRACTED, NULL);
queue_post(&sim_queue, SIM_USB_EXTRACTED, 0);
DEBUGF("USB %s.\n", inserted ? "inserted":"removed");
}
is_usb_inserted = inserted;
}
int usb_detect(void)
{
return is_usb_inserted ? USB_INSERTED : USB_EXTRACTED;
}
void usb_init(void)
{
}
void usb_start_monitoring(void)
{
}
void usb_acknowledge(long id)
{
queue_post(&sim_queue, id, 0);
}
void usb_wait_for_disconnect(struct event_queue *q)
{
struct queue_event ev;
/* Don't return until we get SYS_USB_DISCONNECTED */
while(1)
{
queue_wait(q, &ev);
if(ev.id == SYS_USB_DISCONNECTED)
return;
}
}
static bool is_ext_inserted;
#ifdef HAVE_HOTSWAP
void sim_trigger_external(bool inserted)
{
is_ext_inserted = inserted;
int drive = 1; /* Can do others! */
if (inserted)
queue_post(&sim_queue, SIM_EXT_INSERTED, drive);
else
queue_post(&sim_queue, SIM_EXT_EXTRACTED, drive);
DEBUGF("Ext %s\n", inserted ? "inserted":"removed");
}
#endif
bool hostfs_present(int drive)
{
return drive > 0 ? is_ext_inserted : true;
}
bool hostfs_removable(int drive)
{
return drive > 0;
}
#ifdef HAVE_HOTSWAP
bool volume_removable(int volume)
{
/* volume == drive for now */
return hostfs_removable(volume);
}
bool volume_present(int volume)
{
/* volume == drive for now */
return hostfs_present(volume);
}
#endif /* HAVE_HOTSWAP */
#ifdef HAVE_MULTIDRIVE
int volume_drive(int volume)
{
/* volume == drive for now */
return volume;
}
#endif
#if (CONFIG_STORAGE & STORAGE_MMC)
bool mmc_touched(void)
{
return hostfs_present(1);
}
#endif
#ifdef CONFIG_STORAGE_MULTI
int hostfs_driver_type(int drive)
{
/* Hack alert */
#if (CONFIG_STORAGE & STORAGE_ATA)
#define SIMEXT1_TYPE_NUM STORAGE_ATA_NUM
#elif (CONFIG_STORAGE & STORAGE_SD)
#define SIMEXT1_TYPE_NUM STORAGE_SD_NUM
#elif (CONFIG_STORAGE & STORAGE_MMC)
#define SIMEXT1_TYPE_NUM STORAGE_MMC_NUM
#elif (CONFIG_STORAGE & STORAGE_NAND)
#define SIMEXT1_TYPE_NUM STORAGE_NAND_NUM
#elif (CONFIG_STORAGE & STORAGE_RAMDISK)
#define SIMEXT1_TYPE_NUM STORAGE_RAMDISK_NUM
#elif (CONFIG_STORAGE & STORAGE_USB)
#define SIMEXT1_TYPE_NUM STORAGE_USB_NUM
#else
#error Unknown storage driver
#endif /* CONFIG_STORAGE */
return drive > 0 ? SIMEXT1_TYPE_NUM : STORAGE_HOSTFS_NUM;
}
#endif /* CONFIG_STORAGE_MULTI */
|