usbinit.c
10.1 KB
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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
#include "os.h"
#include "os_bb.h"
#include "osint.h"
#include "host.h"
#include "device.h"
#ifdef USB_DEBUG
/*
* Support for printing to DRAM. Note that USB can
* never call osSyncPrintf, since USB is the low level
* transport for RDB.
*/
/*
* Print buffers in DRAM
*/
int drambufinit = 1;
int drambuflen = 0;
int drambufdisable = 0;
char *drambuf = (char *)PHYS_TO_K1(0x200000);
char *drambufalt = (char *)PHYS_TO_K1(0x280000);
#define DRAMBUFSIZE 0x8000
#ifndef _VA_LIST_
#define _VA_LIST_
typedef char *va_list;
/* va_start makes list point past the parmN */
#define va_start(list, parmN) (list = ((char *)&parmN + sizeof(parmN)))
#define va_end(list)
#endif /* !_VA_LIST_ */
/*
* Shamelessly stolen from monegi/libc/sprintf.c
*/
static void
*proutSprintf(void *s, const char *buf, size_t n)
{
/* write to string */
return ((char *) memcpy(s, buf, n) + n);
}
/*
* Switch print buffers so we can preserve the
* log at points of interest
*/
void
drambufswitch(int what)
{
if (what) {
drambufdisable = what;
}
if (drambuf != drambufalt) {
dramPrintf("***** EOF *****\n");
drambuf = drambufalt;
drambuflen = 0;
}
}
extern int _Printf(void *(*)(void *, const char *, size_t), char *, const char *, va_list);
/*
* Format the output and store it to DRAM, so that
* it can be examined ex post facto ...
*/
int
dramPrintf(const char *fmt, ...)
{
char pbuf[256];
int len;
va_list ap;
OSIntMask im;
if (drambufdisable == 1)
return 0;
im = osSetIntMask(OS_IM_NONE);
if (drambufinit) {
bzero(drambuf, DRAMBUFSIZE);
bzero(drambufalt, DRAMBUFSIZE);
drambufinit = 0;
}
va_start(ap, fmt);
len = _Printf(&proutSprintf, pbuf, fmt, ap);
va_end(ap);
if (len > 0) {
bcopy(pbuf, &drambuf[drambuflen], len);
drambuflen += len;
if (drambuflen > DRAMBUFSIZE) {
if (drambufdisable == 2)
drambufdisable = 1;
else
drambuflen = 0;
}
(void) osSetIntMask(im);
return len;
}
(void) osSetIntMask(im);
return 0;
}
#endif /* USB_DEBUG */
/*
* Static data structures to support the manager threads for
* the USB controllers (one thread and message queue per controller).
*/
static OSThread __osBbUsbMgr[OS_USB_MAX_CONTROLLERS];
static char __osBbUsbMgrStacks[OS_USB_MGR_STACKSIZE * OS_USB_MAX_CONTROLLERS]
__attribute__ ((aligned (8)));
OSMesgQueue __osBbUsbCtlrQ[OS_USB_MAX_CONTROLLERS];
static OSMesg __osBbUsbMesgs[OS_USB_QUEUE_SIZE * OS_USB_MAX_CONTROLLERS];
static __OSBbUsbMesg __osBbUsbEventMesg[OS_USB_MAX_CONTROLLERS];
/*
* Malloc region for ARC service callback structs
*/
void *__usb_svc_callback_reg;
static u8 __usb_svc_callback_buffer[OS_USB_SVC_CALLBACK_SIZE];
/*
* Malloc region for ARC endpoint descriptor structs
*/
void *__usb_endpt_desc_reg;
static u8 __usb_endpt_desc_buffer[OS_USB_ENDPT_DESC_SIZE];
/*
* Message handling routines
*/
static s32
__osBbUsbInterrupt(s32 which, __OSBbUsbMesg *mp)
{
#ifdef USB_DEBUG
if ((which != 0 && (mp->um_type != OS_USB_MESG_INT1))
|| ((which == 0) && (mp->um_type != OS_USB_MESG_INT0))) {
PRINTF("Wrong INT message type %d!\n", mp->um_type);
}
#endif
return(__usbDevInterrupt(which));
}
extern void __usbDevRead(_usb_ext_handle *);
static s32
__osBbUsbRead(s32 which, __OSBbUsbMesg *ump)
{
_usb_ext_handle *uhp;
uhp = (_usb_ext_handle *) ump->u.umrw.umrw_handle;
/*
* Make sure the device hasn't been detached out
* from under us
*/
if (uhp->uh_host_handle == NULL) {
PRINTF("==UsbRead%d: device went away\n", which);
return(-EUSBNXIO);
}
if (uhp->uh_rd_msg != NULL) {
PRINTF("==UsbRead%d: write already in progress\n", which);
return(-EUSBBUSY);
}
/*
* Record information for IO
*/
uhp->uh_rd_msg = ump;
uhp->uh_rd_buffer = ump->u.umrw.umrw_buffer;
uhp->uh_rd_offset = ump->u.umrw.umrw_offset;
uhp->uh_rd_len = ump->u.umrw.umrw_len;
#if 0
/*
* At this layer, the request is already sized for
* the device. Hand it off to the device.
*/
if (uhp->uh_rd_len > uhp->uh_blksize) {
PRINTF("==UsbRead read too long %d (reset to %d)\n", uhp->uh_rd_len, uhp->uh_blksize);
uhp->uh_rd_len = uhp->uh_blksize;
}
#endif
__usbDevRead(uhp);
return(0);
}
extern void __usbDevWrite(_usb_ext_handle *);
static s32
__osBbUsbWrite(s32 which, __OSBbUsbMesg *ump)
{
_usb_ext_handle *uhp;
uhp = (_usb_ext_handle *) ump->u.umrw.umrw_handle;
/*
* Make sure the device hasn't been detached out
* from under us
*/
if (uhp->uh_host_handle == NULL) {
PRINTF("==UsbWrite%d: device went away\n", which);
return(-EUSBNXIO);
}
if (uhp->uh_wr_msg != NULL) {
PRINTF("==UsbWrite%d: write already in progress\n", which);
return(-EUSBBUSY);
}
/*
* Record information for IO
*/
uhp->uh_wr_msg = ump;
uhp->uh_wr_buffer = ump->u.umrw.umrw_buffer;
uhp->uh_wr_offset = ump->u.umrw.umrw_offset;
uhp->uh_wr_len = ump->u.umrw.umrw_len;
#if 0
/*
* At this layer, the request is already sized for
* the device. Hand it off to the device.
*/
if (uhp->uh_wr_len > uhp->uh_blksize) {
PRINTF("==UsbWrite write too long %d (reset to %d)\n", uhp->uh_wr_len, uhp->uh_blksize);
uhp->uh_wr_len = uhp->uh_blksize;
}
#endif
__usbDevWrite(uhp);
return(0);
}
/*
* Manager Thread process for each USB controller
*/
static void
__osBbUsbMgrProc(char *arg)
{
OSMesgQueue *mq;
OSMesg msg;
__OSBbUsbMesg *mp;
OSId myid;
s32 ret = 0;
s32 which;
mq = (OSMesgQueue *)arg;
myid = osGetThreadId(NULL);
which = myid - OS_USB_TID_BASE;
/*
* Loop forever processing messages on the input queue
*/
while (1) {
(void)osRecvMesg(mq, &msg, OS_MESG_BLOCK);
mp = msg;
switch (mp->um_type) {
case OS_USB_MESG_INT0:
case OS_USB_MESG_INT1:
ret = __osBbUsbInterrupt(which, mp);
break;
case OS_USB_MESG_READ:
ret = __osBbUsbRead(which, mp);
break;
case OS_USB_MESG_WRITE:
ret = __osBbUsbWrite(which, mp);
break;
default:
PRINTF("unknown\n");
ret = EUSBRINVAL;
break;
}
/*
* Send reply only for errors at this level.
* Interrupts require no reply. For reads and
* writes, the reply will be sent when the
* transaction completes.
*/
if (ret == 0)
continue;
mp->um_type |= OS_USB_REPLY_MASK;
mp->um_ret = ret;
if (osSendMesg(mp->um_rq, (void *)mp, OS_MESG_NOBLOCK) < 0) {
PRINTF("USBMgr%d: reply queue full!\n", myid);
}
}
}
/*
* __osBbUsbThreadInit
*
* Description:
* Must be called to start the manager thread for each
* USB controller.
*
* Returns:
* 0 for success
* -1 for failure (sets error code?)
*/
static s32
__osBbUsbThreadInit(s32 which)
{
/*
* XXX XXX
* If the manager thread is acting as a USB Slave,
* then its priority needs to be higher to avoid
* pseudo-deadlocks in the loopback case. If we
* can solve the busy-wait problem in _us_host_delay,
* this may no longer be necessary. (Use osSetTimer?)
*
* For the moment, we continue the hack of assuming that
* USB1 is a Slave.
* XXX XXX
*/
/*
* Just create the thread for now
*/
if (which < 0 || which >= OS_USB_MAX_CONTROLLERS) {
PRINTF("__osBbUsbContInit called with bad arg %d\n", which);
return(-1);
}
osCreateMesgQueue(&__osBbUsbCtlrQ[which],
&__osBbUsbMesgs[OS_USB_QUEUE_SIZE * which],
OS_USB_QUEUE_SIZE);
osCreateThread(&__osBbUsbMgr[which],
OS_USB_TID_BASE+which,
(void(*)(void *))__osBbUsbMgrProc,
(void *)&__osBbUsbCtlrQ[which],
(void *)&__osBbUsbMgrStacks[OS_USB_MGR_STACKSIZE*(which+1)],
(which == 1) ? OS_USB_THREAD_PRI_HOST : OS_USB_THREAD_PRI_DEV);
osStartThread(&__osBbUsbMgr[which]);
/*
* Manager thread fields event messages from interrupts as
* well as API requests. This is done using two static
* messages, one for each controller. These are never
* freed or used for anything other than delivery of events.
* In fact, it may be the case that the same message can
* be queued multiple times if more than one interrupt
* comes in before the manager thread can run.
* XXX can this happen and is it a problem? XXX
*/
bzero((void *)&__osBbUsbEventMesg[which], sizeof (__OSBbUsbMesg));
__osBbUsbEventMesg[which].um_type =
(which ? OS_USB_MESG_INT1 : OS_USB_MESG_INT0);
osSetEventMesg((which ? OS_EVENT_USB1 : OS_EVENT_USB0),
&__osBbUsbCtlrQ[which],
&__osBbUsbEventMesg[which]);
return(0);
}
#ifdef USB_HOST
#ifdef USB_ECHO_HOST
extern usb_host_driver echo_host_driver;
#endif
#ifdef USB_RDB_HOST
extern usb_host_driver rdbs_host_driver;
#endif
#endif /* USB_HOST */
/*
* osBbUsbSetCtlrMode
*
* Description:
* Controls the behavior of the specified USB controller.
* The mask value determines the behavior of the specified
* USB controller:
*
* OS_USB_TYPE_DISABLED
* OS_USB_TYPE_HOST
* OS_USB_TYPE_DEVICE
* OS_USB_TYPE_EITHER
*
* A subsequent call to osBbUsbInit is required for the
* results of this call to take effect.
*
* Returns:
* 0 if successful
* < 0 if parameter error or other failure
*/
s32
osBbUsbSetCtlrModes(s32 which, u32 mask)
{
if (which < 0 || which >= OS_USB_MAX_CONTROLLERS) {
return(-1);
}
_usb_ctlr_state[which].ucs_mask = mask;
/*
* Clear any disallowed mode that is currently in force.
* XXX clear any associated state?
*/
_usb_ctlr_state[which].ucs_mode &= ~mask;
return(0);
}
/*
* osBbUsbInit
*
* Description:
* Must be called by an application that wishes to do USB io
*
* Returns:
* Number of USB controllers present (0 if none)
*/
s32
osBbUsbInit(void)
{
s32 i, numctlr = 0;
/*
* Create malloc region for service callback structs
*/
__usb_svc_callback_reg = osCreateRegion(
(void *)__usb_svc_callback_buffer,
sizeof (__usb_svc_callback_buffer),
sizeof (USB_SERVICE_STRUCT),
0);
/*
* Create malloc region for endpoint descriptor structs
*/
__usb_endpt_desc_reg = osCreateRegion(
(void *)__usb_endpt_desc_buffer,
sizeof (__usb_endpt_desc_buffer),
sizeof (XD_STRUCT) * OS_USB_MAX_ENDPTS,
0);
/*
* Create and start the manager threads
*/
for (i = 0; i < OS_USB_MAX_CONTROLLERS; i++) {
if (__osBbUsbThreadInit(i) == 0)
numctlr++;
}
/*
* Initialize the host device-specific drivers that are included
*/
#ifdef USB_HOST
#ifdef USB_RDB_HOST
__usb_host_driver_register(&rdbs_host_driver);
#endif
#ifdef USB_ECHO_HOST
__usb_host_driver_register(&echo_host_driver);
#endif
#endif /* USB_HOST */
/*
* Initialize the hardware
*/
__usbHwInit();
return(numctlr);
}