Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
15 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
6
//    This file is part of emBIOS.
7
//
8
//    emBIOS is free software: you can redistribute it and/or
9
//    modify it under the terms of the GNU General Public License as
10
//    published by the Free Software Foundation, either version 2 of the
11
//    License, or (at your option) any later version.
12
//
13
//    emBIOS is distributed in the hope that it will be useful,
14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
//    See the GNU General Public License for more details.
17
//
18
//    You should have received a copy of the GNU General Public License along
19
//    with emBIOS.  If not, see <http://www.gnu.org/licenses/>.
20
//
21
//
22
 
23
 
24
#include "global.h"
25
#include "panic.h"
26
#include "usb.h"
27
#include "usb_ch9.h"
28
#include "usbdrv.h"
29
#include "thread.h"
30
#include "console.h"
31
#include "util.h"
32
#include "i2c.h"
25 theseven 33
#include "strlen.h"
34
#include "contextswitch.h"
29 theseven 35
#include "pmu.h"
36
#include "shutdown.h"
15 theseven 37
 
38
 
39
static uint8_t ctrlresp[2] CACHEALIGN_ATTR;
40
static uint32_t dbgrecvbuf[0x80] CACHEALIGN_ATTR;
41
static uint32_t dbgsendbuf[0x80] CACHEALIGN_ATTR;
42
static uint32_t dbgasyncsendbuf[0x80] CACHEALIGN_ATTR;
43
static char dbgendpoints[4] IBSS_ATTR;
44
 
45
enum dbgaction_t
46
{
47
    DBGACTION_IDLE = 0,
48
    DBGACTION_I2CSEND,
49
    DBGACTION_I2CRECV,
29 theseven 50
    DBGACTION_RESET,
51
    DBGACTION_POWEROFF,
52
    DBGACTION_CWRITE,
53
    DBGACTION_CREAD,
54
    DBGACTION_CFLUSH
15 theseven 55
};
56
 
57
static uint32_t dbgstack[0x100] STACK_ATTR;
58
struct wakeup dbgwakeup IBSS_ATTR;
59
extern struct scheduler_thread* scheduler_threads;
60
static enum dbgaction_t dbgaction IBSS_ATTR;
29 theseven 61
static int dbgi2cbus;
62
static int dbgi2cslave;
63
static int dbgactionaddr;
64
static int dbgactionlength;
65
static int dbgactionconsoles;
66
static int dbgactiontype;
25 theseven 67
static char dbgconsendbuf[4096];
68
static char dbgconrecvbuf[1024];
69
static int dbgconsendreadidx IBSS_ATTR;
70
static int dbgconsendwriteidx IBSS_ATTR;
71
static int dbgconrecvreadidx IBSS_ATTR;
72
static int dbgconrecvwriteidx IBSS_ATTR;
73
static struct wakeup dbgconsendwakeup IBSS_ATTR;
74
static struct wakeup dbgconrecvwakeup IBSS_ATTR;
75
static bool dbgconsoleattached IBSS_ATTR;
15 theseven 76
 
25 theseven 77
static const char dbgconoverflowstr[] = "\n\n[overflowed]\n\n";
15 theseven 78
 
25 theseven 79
 
15 theseven 80
static struct usb_device_descriptor CACHEALIGN_ATTR device_descriptor =
81
{
82
    .bLength            = sizeof(struct usb_device_descriptor),
83
    .bDescriptorType    = USB_DT_DEVICE,
84
    .bcdUSB             = 0x0200,
85
    .bDeviceClass       = USB_CLASS_VENDOR_SPEC,
86
    .bDeviceSubClass    = 0xff,
87
    .bDeviceProtocol    = 0xff,
88
    .bMaxPacketSize0    = 64,
89
    .idVendor           = 0xffff,
90
    .idProduct          = 0xe000,
91
    .bcdDevice          = 0x0001,
92
    .iManufacturer      = 1,
93
    .iProduct           = 2,
94
    .iSerialNumber      = 0,
95
    .bNumConfigurations = 1
96
};
97
 
98
static struct usb_config_bundle
99
{
100
    struct usb_config_descriptor config_descriptor;
101
    struct usb_interface_descriptor interface_descriptor;
102
    struct usb_endpoint_descriptor endpoint1_descriptor;
103
    struct usb_endpoint_descriptor endpoint2_descriptor;
104
    struct usb_endpoint_descriptor endpoint3_descriptor;
105
    struct usb_endpoint_descriptor endpoint4_descriptor;
106
} __attribute__((packed)) CACHEALIGN_ATTR config_bundle = 
107
{
108
    .config_descriptor =
109
    {
110
        .bLength             = sizeof(struct usb_config_descriptor),
111
        .bDescriptorType     = USB_DT_CONFIG,
112
        .wTotalLength        = sizeof(struct usb_config_descriptor)
113
                             + sizeof(struct usb_interface_descriptor)
114
                             + sizeof(struct usb_endpoint_descriptor) * 4,
115
        .bNumInterfaces      = 1,
116
        .bConfigurationValue = 1,
117
        .iConfiguration      = 0,
118
        .bmAttributes        = USB_CONFIG_ATT_ONE,
119
        .bMaxPower           = 250
120
    },
121
    .interface_descriptor =
122
    {
123
        .bLength             = sizeof(struct usb_interface_descriptor),
124
        .bDescriptorType     = USB_DT_INTERFACE,
125
        .bInterfaceNumber    = 0,
126
        .bAlternateSetting   = 0,
127
        .bNumEndpoints       = 4,
128
        .bInterfaceClass     = USB_CLASS_VENDOR_SPEC,
129
        .bInterfaceSubClass  = 0xff,
130
        .bInterfaceProtocol  = 0xff,
131
        .iInterface          = 0
132
    },
133
    .endpoint1_descriptor =
134
    {
135
        .bLength             = sizeof(struct usb_endpoint_descriptor),
136
        .bDescriptorType     = USB_DT_ENDPOINT,
137
        .bEndpointAddress    = 0,
138
        .bmAttributes        = USB_ENDPOINT_XFER_BULK,
139
        .wMaxPacketSize      = 0,
140
        .bInterval           = 1
141
    },
142
    .endpoint2_descriptor =
143
    {
144
        .bLength             = sizeof(struct usb_endpoint_descriptor),
145
        .bDescriptorType     = USB_DT_ENDPOINT,
146
        .bEndpointAddress    = 0,
147
        .bmAttributes        = USB_ENDPOINT_XFER_BULK,
148
        .wMaxPacketSize      = 0,
149
        .bInterval           = 1
150
    },
151
    .endpoint3_descriptor =
152
    {
153
        .bLength             = sizeof(struct usb_endpoint_descriptor),
154
        .bDescriptorType     = USB_DT_ENDPOINT,
155
        .bEndpointAddress    = 0,
156
        .bmAttributes        = USB_ENDPOINT_XFER_BULK,
157
        .wMaxPacketSize      = 0,
158
        .bInterval           = 1
159
    },
160
    .endpoint4_descriptor =
161
    {
162
        .bLength             = sizeof(struct usb_endpoint_descriptor),
163
        .bDescriptorType     = USB_DT_ENDPOINT,
164
        .bEndpointAddress    = 0,
165
        .bmAttributes        = USB_ENDPOINT_XFER_BULK,
166
        .wMaxPacketSize      = 0,
167
        .bInterval           = 1
168
    }
169
};
170
 
171
static struct usb_string_descriptor CACHEALIGN_ATTR string_devicename =
172
{
173
    32,
174
    USB_DT_STRING,
175
    {'e', 'm', 'B', 'I', 'O', 'S', ' ', 'D', 'e', 'b', 'u', 'g', 'g', 'e', 'r'}
176
};
177
 
178
static const struct usb_string_descriptor CACHEALIGN_ATTR lang_descriptor =
179
{
180
    4,
181
    USB_DT_STRING,
182
    {0x0409}
183
};
184
 
185
 
186
void usb_setup_dbg_listener()
187
{
188
    usb_drv_recv(dbgendpoints[0], dbgrecvbuf, usb_drv_port_speed() ? 512 : 64);
189
}
190
 
191
void usb_handle_control_request(struct usb_ctrlrequest* req)
192
{
193
    const void* addr;
194
    int size = -1;
195
    switch (req->bRequest)
196
    {
197
    case USB_REQ_GET_STATUS:
198
        if (req->bRequestType == USB_DIR_IN) ctrlresp[0] = 1;
199
        else ctrlresp[0] = 0;
200
        ctrlresp[1] = 0;
201
        addr = ctrlresp;
202
        size = 2;
203
        break;
204
    case USB_REQ_CLEAR_FEATURE:
205
        if (req->bRequestType == USB_RECIP_ENDPOINT && req->wValue == USB_ENDPOINT_HALT)
206
            usb_drv_stall(req->wIndex & 0xf, false, req->wIndex >> 7);
207
        size = 0;
208
        break;
209
    case USB_REQ_SET_FEATURE:
210
        size = 0;
211
        break;
212
    case USB_REQ_SET_ADDRESS:
213
        size = 0;
214
        usb_drv_cancel_all_transfers();
215
        usb_drv_set_address(req->wValue);
216
        usb_setup_dbg_listener();
217
        break;
218
    case USB_REQ_GET_DESCRIPTOR:
219
        switch (req->wValue >> 8)
220
        {
221
        case USB_DT_DEVICE:
222
            addr = &device_descriptor;
223
            size = sizeof(device_descriptor);
224
            break;
225
        case USB_DT_OTHER_SPEED_CONFIG:
226
        case USB_DT_CONFIG:
227
            if ((req->wValue >> 8) == USB_DT_CONFIG)
228
            {
229
                int maxpacket = usb_drv_port_speed() ? 512 : 64;
230
                config_bundle.endpoint1_descriptor.wMaxPacketSize = maxpacket;
231
                config_bundle.endpoint2_descriptor.wMaxPacketSize = maxpacket;
232
                config_bundle.endpoint3_descriptor.wMaxPacketSize = maxpacket;
233
                config_bundle.endpoint4_descriptor.wMaxPacketSize = maxpacket;
234
                config_bundle.config_descriptor.bDescriptorType = USB_DT_CONFIG;
235
            }
236
            else
237
            {
238
                int maxpacket = usb_drv_port_speed() ? 64 : 512;
239
                config_bundle.endpoint1_descriptor.wMaxPacketSize = maxpacket;
240
                config_bundle.endpoint2_descriptor.wMaxPacketSize = maxpacket;
241
                config_bundle.endpoint3_descriptor.wMaxPacketSize = maxpacket;
242
                config_bundle.endpoint4_descriptor.wMaxPacketSize = maxpacket;
243
                config_bundle.config_descriptor.bDescriptorType = USB_DT_OTHER_SPEED_CONFIG;
244
            }
245
            addr = &config_bundle;
246
            size = sizeof(config_bundle);
247
            break;
248
        case USB_DT_STRING:
249
            switch (req->wValue & 0xff)
250
            {
251
            case 0:
252
                addr = &lang_descriptor;
253
                size = sizeof(lang_descriptor);
254
                break;
255
            case 1:
256
                string_devicename.bLength = 14;
257
                addr = &string_devicename;
258
                size = 14;
259
            case 2:
260
                string_devicename.bLength = sizeof(string_devicename);
261
                addr = &string_devicename;
262
                size = sizeof(string_devicename);
263
                break;
264
            }
265
            break;
266
        }
267
        break;
268
    case USB_REQ_GET_CONFIGURATION:
269
        ctrlresp[0] = 1;
270
        addr = ctrlresp;
271
        size = 1;
272
        break;
273
    case USB_REQ_SET_CONFIGURATION:
274
        usb_drv_cancel_all_transfers();
275
        usb_setup_dbg_listener();
276
        size = 0;
277
        break;
278
    }
279
    if (!size) usb_drv_send_nonblocking(0, NULL, 0);
280
    else if (size == -1)
281
    {
282
        usb_drv_stall(0, true, true);
283
        usb_drv_stall(0, true, false);
284
    }
285
    else
286
    {
287
        usb_drv_recv(0, NULL, 0);
288
        usb_drv_send_nonblocking(0, addr, size > req->wLength ? req->wLength : size);
289
    }
290
}
291
 
29 theseven 292
bool set_dbgaction(enum dbgaction_t action, int addsize)
15 theseven 293
{
294
    if (dbgaction != DBGACTION_IDLE)
295
    {
296
        dbgsendbuf[0] = 3;
29 theseven 297
        usb_drv_send_nonblocking(dbgendpoints[1], dbgsendbuf, 16 + addsize);
15 theseven 298
        return true;
299
    }
300
    dbgaction = action;
301
    wakeup_signal(&dbgwakeup);
302
    return false;
303
}
304
 
305
void reset() __attribute__((noreturn));
306
 
307
void usb_handle_transfer_complete(int endpoint, int dir, int status, int length)
308
{
309
    void* addr = dbgsendbuf;
310
    int size = 0;
311
    if (endpoint == dbgendpoints[0])
312
    {
313
        switch (dbgrecvbuf[0])
314
        {
28 theseven 315
        case 1:  // GET INFO
15 theseven 316
            dbgsendbuf[0] = 1;
317
            size = 16;
28 theseven 318
            switch (dbgrecvbuf[1])
319
            {
320
            case 0:  // GET VERSION INFO
321
                dbgsendbuf[1] = VERSION_MAJOR | (VERSION_MINOR << 8)
322
                              | (VERSION_PATCH << 16) | (1 << 24);
323
                dbgsendbuf[2] = PLATFORM_ID;
324
                dbgsendbuf[3] = VERSION_SVN_INT;
325
                break;
326
            case 1:  // GET PACKET SIZE INFO
327
                dbgsendbuf[1] = 0x02000200;
328
                dbgsendbuf[2] = usb_drv_get_max_out_size();
329
                dbgsendbuf[3] = usb_drv_get_max_in_size();
330
                break;
331
            default:
332
                dbgsendbuf[0] = 2;
333
            }
15 theseven 334
            break;
335
        case 2:  // RESET
29 theseven 336
            if (dbgrecvbuf[1])
337
            {
338
                if (set_dbgaction(DBGACTION_RESET, 0)) break;
339
                dbgsendbuf[0] = 1;
340
                size = 16;
341
            }
342
            else reset();
15 theseven 343
            break;
344
        case 3:  // POWER OFF
29 theseven 345
            if (set_dbgaction(DBGACTION_POWEROFF, 0)) break;
346
            dbgactiontype = dbgrecvbuf[1];
347
            dbgsendbuf[0] = 1;
348
            size = 16;
15 theseven 349
            break;
350
        case 4:  // READ MEMORY
351
            dbgsendbuf[0] = 1;
352
            memcpy(&dbgsendbuf[4], (const void*)dbgrecvbuf[1], dbgrecvbuf[2]);
353
            size = dbgrecvbuf[2] + 16;
354
            break;
355
        case 5:  // WRITE MEMORY
356
            dbgsendbuf[0] = 1;
357
            memcpy((void*)dbgrecvbuf[1], &dbgrecvbuf[4], dbgrecvbuf[2]);
358
            size = 16;
359
            break;
360
        case 6:  // READ DMA
361
            dbgsendbuf[0] = 1;
362
            usb_drv_send_nonblocking(dbgendpoints[1], dbgsendbuf, 16);
363
            usb_drv_send_nonblocking(dbgendpoints[3], (const void*)dbgrecvbuf[1], dbgrecvbuf[2]);
364
            break;
365
        case 7:  // WRITE DMA
366
            dbgsendbuf[0] = 1;
367
            size = 16;
368
            usb_drv_recv(dbgendpoints[2], (void*)dbgrecvbuf[1], dbgrecvbuf[2]);
369
            break;
370
        case 8:  // READ I2C
29 theseven 371
            if (set_dbgaction(DBGACTION_I2CRECV, dbgrecvbuf[1] >> 24)) break;
15 theseven 372
            dbgi2cbus = dbgrecvbuf[1] & 0xff;
373
            dbgi2cslave = (dbgrecvbuf[1] >> 8) & 0xff;
29 theseven 374
            dbgactionaddr = (dbgrecvbuf[1] >> 16) & 0xff;
375
            dbgactionlength = dbgrecvbuf[1] >> 24;
15 theseven 376
            break;
377
        case 9:  // WRITE I2C
29 theseven 378
            if (set_dbgaction(DBGACTION_I2CSEND, 0)) break;
15 theseven 379
            dbgi2cbus = dbgrecvbuf[1] & 0xff;
380
            dbgi2cslave = (dbgrecvbuf[1] >> 8) & 0xff;
29 theseven 381
            dbgactionaddr = (dbgrecvbuf[1] >> 16) & 0xff;
382
            dbgactionlength = dbgrecvbuf[1] >> 24;
383
            memcpy(dbgasyncsendbuf, &dbgsendbuf[4], dbgactionlength);
15 theseven 384
            break;
25 theseven 385
        case 10:  // READ CONSOLE
386
            dbgconsoleattached = true;
387
            int bytes = dbgconsendwriteidx - dbgconsendreadidx;
388
            if (bytes >= sizeof(dbgconsendbuf)) bytes -= sizeof(dbgconsendbuf);
389
            if (bytes)
390
            {
391
                if (bytes < 0) bytes += sizeof(dbgconsendbuf);
392
                if (bytes > dbgrecvbuf[1]) bytes = dbgrecvbuf[1];
393
                int readbytes = bytes;
394
                char* outptr = (char*)&dbgsendbuf[4];
395
                if (dbgconsendreadidx + bytes >= sizeof(dbgconsendbuf))
396
                {
397
                    readbytes = sizeof(dbgconsendbuf) - dbgconsendreadidx;
398
                    memcpy(outptr, &dbgconsendbuf[dbgconsendreadidx], readbytes);
399
                    dbgconsendreadidx = 0;
400
                    outptr = &outptr[readbytes];
401
                    readbytes = bytes - readbytes;
402
                }
403
                if (readbytes) memcpy(outptr, &dbgconsendbuf[dbgconsendreadidx], readbytes);
404
                dbgconsendreadidx += readbytes;
26 theseven 405
                wakeup_signal(&dbgconsendwakeup);
25 theseven 406
            }
407
            dbgsendbuf[0] = 1;
408
            dbgsendbuf[1] = bytes;
409
            dbgsendbuf[2] = sizeof(dbgconsendbuf);
410
            dbgsendbuf[3] = dbgconsendwriteidx - dbgconsendreadidx;
411
            size = 16 + dbgrecvbuf[1];
412
            break;
26 theseven 413
        case 11:  // WRITE CONSOLE
414
            bytes = dbgconrecvreadidx - dbgconrecvwriteidx - 1;
415
            if (bytes < 0) bytes += sizeof(dbgconrecvbuf);
416
            if (bytes)
417
            {
418
                if (bytes > dbgrecvbuf[1]) bytes = dbgrecvbuf[1];
419
                int writebytes = bytes;
420
                char* readptr = (char*)&dbgrecvbuf[4];
421
                if (dbgconrecvwriteidx + bytes >= sizeof(dbgconrecvbuf))
422
                {
423
                    writebytes = sizeof(dbgconrecvbuf) - dbgconrecvwriteidx;
424
                    memcpy(&dbgconrecvbuf[dbgconrecvwriteidx], readptr, writebytes);
425
                    dbgconrecvwriteidx = 0;
426
                    readptr = &readptr[writebytes];
427
                    writebytes = bytes - writebytes;
428
                }
429
                if (writebytes) memcpy(&dbgconrecvbuf[dbgconrecvwriteidx], readptr, writebytes);
430
                dbgconrecvwriteidx += writebytes;
431
                wakeup_signal(&dbgconrecvwakeup);
432
            }
433
            dbgsendbuf[0] = 1;
434
            dbgsendbuf[1] = bytes;
435
            dbgsendbuf[2] = sizeof(dbgconrecvbuf);
436
            dbgsendbuf[3] = dbgconrecvreadidx - dbgconrecvwriteidx - 1;
437
            size = 16;
438
            break;
29 theseven 439
        case 12:  // CWRITE
440
            if (set_dbgaction(DBGACTION_CWRITE, 0)) break;
441
            dbgactionconsoles = dbgrecvbuf[1];
442
            dbgactionlength = dbgrecvbuf[2];
443
            memcpy(dbgasyncsendbuf, &dbgrecvbuf[4], dbgactionlength);
444
            break;
445
        case 13:  // CREAD
446
            if (set_dbgaction(DBGACTION_CREAD, dbgrecvbuf[2])) break;
447
            dbgactionconsoles = dbgrecvbuf[1];
448
            dbgactionlength = dbgrecvbuf[2];
449
            break;
450
        case 14:  // CFLUSH
451
            if (set_dbgaction(DBGACTION_CFLUSH, 0)) break;
452
            dbgactionconsoles = dbgrecvbuf[1];
453
            break;
31 theseven 454
        case 15:  // GET PROCESS INFO
455
            dbgsendbuf[0] = 1;
456
            dbgsendbuf[1] = SCHEDULER_THREAD_INFO_VERSION;
457
            dbgsendbuf[2] = MAX_THREADS * sizeof(struct scheduler_thread);
458
            memcpy(&dbgsendbuf[4], scheduler_threads, dbgrecvbuf[1]);
459
            size = dbgrecvbuf[1] + 16;
460
            break;
34 theseven 461
        case 16:  // FREEZE SCHEDULER
462
            scheduler_freeze(dbgrecvbuf[1]);
463
            dbgsendbuf[0] = 1;
464
            size = 16;
465
            break;
15 theseven 466
        default:
467
            dbgsendbuf[0] = 2;
468
            size = 16;
469
        }
470
        usb_setup_dbg_listener();
471
        if (size) usb_drv_send_nonblocking(dbgendpoints[1], addr, size);
472
    }
473
}
474
 
475
void usb_handle_bus_reset(void)
476
{
477
    dbgendpoints[0] = usb_drv_request_endpoint(USB_ENDPOINT_XFER_BULK, USB_DIR_OUT);
478
    dbgendpoints[1] = usb_drv_request_endpoint(USB_ENDPOINT_XFER_BULK, USB_DIR_IN);
479
    dbgendpoints[2] = usb_drv_request_endpoint(USB_ENDPOINT_XFER_BULK, USB_DIR_OUT);
480
    dbgendpoints[3] = usb_drv_request_endpoint(USB_ENDPOINT_XFER_BULK, USB_DIR_IN);
481
    config_bundle.endpoint1_descriptor.bEndpointAddress = dbgendpoints[0];
482
    config_bundle.endpoint2_descriptor.bEndpointAddress = dbgendpoints[1];
483
    config_bundle.endpoint3_descriptor.bEndpointAddress = dbgendpoints[2];
484
    config_bundle.endpoint4_descriptor.bEndpointAddress = dbgendpoints[3];
485
    usb_setup_dbg_listener();
486
}
487
 
488
void dbgthread(void)
489
{
490
    int i;
25 theseven 491
    int t;
15 theseven 492
    while (1)
493
    {
494
        wakeup_wait(&dbgwakeup, TIMEOUT_BLOCK);
495
        for (i = 0; i < MAX_THREADS; i++)
496
            if (scheduler_threads[i].state == THREAD_DEFUNCT)
497
            {
498
                if (scheduler_threads[i].block_type == THREAD_DEFUNCT_STKOV)
499
                    cprintf(1, "\n*PANIC*\nStack overflow! (%s)\n",
500
                            scheduler_threads[i].name);
501
                scheduler_threads[i].state = THREAD_DEFUNCT_ACK;
502
            }
503
        if (dbgaction != DBGACTION_IDLE)
504
        {
505
            switch (dbgaction)
506
            {
507
            case DBGACTION_I2CSEND:
29 theseven 508
                i2c_send(dbgi2cbus, dbgi2cslave, dbgactionaddr,
509
                         (uint8_t*)dbgasyncsendbuf, dbgactionlength);
15 theseven 510
                dbgasyncsendbuf[0] = 1;
511
                usb_drv_send_nonblocking(dbgendpoints[1], dbgasyncsendbuf, 16);
512
                break;
513
            case DBGACTION_I2CRECV:
29 theseven 514
                i2c_recv(dbgi2cbus, dbgi2cslave, dbgactionaddr,
515
                         (uint8_t*)(&dbgasyncsendbuf[4]), dbgactionlength);
15 theseven 516
                dbgasyncsendbuf[0] = 1;
29 theseven 517
                usb_drv_send_nonblocking(dbgendpoints[1], dbgasyncsendbuf, 16 + dbgactionlength);
15 theseven 518
                break;
519
            case DBGACTION_POWEROFF:
29 theseven 520
                if (dbgactiontype) shutdown();
521
                poweroff();
15 theseven 522
                break;
29 theseven 523
            case DBGACTION_RESET:
524
                shutdown();
525
                reset();
526
                break;
527
            case DBGACTION_CWRITE:
528
                cwrite(dbgactionconsoles, (const char*)dbgasyncsendbuf, dbgactionlength);
529
                dbgasyncsendbuf[0] = 1;
530
                usb_drv_send_nonblocking(dbgendpoints[1], dbgasyncsendbuf, 16);
531
                break;
532
            case DBGACTION_CREAD:
533
                dbgasyncsendbuf[0] = 1;
30 theseven 534
                dbgasyncsendbuf[1] = cread(dbgactionconsoles, (char*)&dbgasyncsendbuf[4],
535
                                           dbgactionlength, 0);
29 theseven 536
                usb_drv_send_nonblocking(dbgendpoints[1], dbgasyncsendbuf, 16);
537
                break;
538
            case DBGACTION_CFLUSH:
539
                cflush(dbgactionconsoles);
540
                dbgasyncsendbuf[0] = 1;
541
                usb_drv_send_nonblocking(dbgendpoints[1], dbgasyncsendbuf, 16);
542
                break;
15 theseven 543
            }
544
            dbgaction = DBGACTION_IDLE;
545
        }
546
    }
547
}
548
 
549
void usb_init(void)
550
{
551
    dbgaction = DBGACTION_IDLE;
552
    wakeup_init(&dbgwakeup);
25 theseven 553
    dbgconsendreadidx = 0;
554
    dbgconsendwriteidx = 0;
555
    dbgconrecvreadidx = 0;
556
    dbgconrecvwriteidx = 0;
557
    wakeup_init(&dbgconsendwakeup);
558
    wakeup_init(&dbgconrecvwakeup);
559
    dbgconsoleattached = false;;
15 theseven 560
    thread_create("Debugger", dbgthread, dbgstack, sizeof(dbgstack), 255, SYSTEM_THREAD, true);
561
    usb_drv_init();
562
}
25 theseven 563
 
564
int dbgconsole_getfree() ICODE_ATTR;
565
int dbgconsole_getfree()
566
{
567
    int free = dbgconsendreadidx - dbgconsendwriteidx - 1;
568
    if (free < 0) free += sizeof(dbgconsendbuf);
569
    return free;
570
}
571
 
572
int dbgconsole_makespace(int length) ICODE_ATTR;
573
int dbgconsole_makespace(int length)
574
{
575
    int free = dbgconsole_getfree();
576
    while (!free && dbgconsoleattached)
577
    {
578
        if (wakeup_wait(&dbgconsendwakeup, 2000000) == THREAD_TIMEOUT)
579
            dbgconsoleattached = false;
580
        free = dbgconsole_getfree();
581
    }
582
    if (free) return free > length ? length : free;
583
    if (length > sizeof(dbgconsendbuf) - 17) length = sizeof(dbgconsendbuf) - 17;
584
    uint32_t mode = enter_critical_section();
585
    dbgconsendreadidx += length;
586
    if (dbgconsendreadidx >= sizeof(dbgconsendbuf))
587
        dbgconsendreadidx -= sizeof(dbgconsendbuf);
588
    int offset = 0;
589
    int idx = dbgconsendreadidx;
590
    if (idx + 16 >= sizeof(dbgconsendbuf))
591
    {
592
        offset = sizeof(dbgconsendbuf) - dbgconsendreadidx;
593
        memcpy(&dbgconsendbuf[dbgconsendreadidx], dbgconoverflowstr, offset);
594
        idx = 0;
595
    }
596
    if (offset != 16) memcpy(&dbgconsendbuf[idx], &dbgconoverflowstr[offset], 16 - offset);
597
    leave_critical_section(mode);
598
    return length;
599
}
600
 
601
void dbgconsole_putc(char string)
602
{
603
    dbgconsole_makespace(1);
604
    dbgconsendbuf[dbgconsendwriteidx++] = string;
605
    if (dbgconsendwriteidx >= sizeof(dbgconsendbuf))
606
        dbgconsendwriteidx -= sizeof(dbgconsendbuf);
607
}
608
 
609
void dbgconsole_write(const char* string, size_t length)
610
{
611
    while (length)
612
    {
613
        int space = dbgconsole_makespace(length);
614
        if (dbgconsendwriteidx + space >= sizeof(dbgconsendbuf))
615
        {
616
            int bytes = sizeof(dbgconsendbuf) - dbgconsendwriteidx;
617
            memcpy(&dbgconsendbuf[dbgconsendwriteidx], string, bytes);
618
            dbgconsendwriteidx = 0;
619
            string = &string[bytes];
620
            space -= bytes;
621
            length -= bytes;
622
        }
623
        if (space) memcpy(&dbgconsendbuf[dbgconsendwriteidx], string, space);
624
        dbgconsendwriteidx += space;
625
        string = &string[space];
626
        length -= space;
627
    }
628
}
629
 
630
void dbgconsole_puts(const char* string)
631
{
632
    dbgconsole_write(string, strlen(string));
633
}
26 theseven 634
 
635
int dbgconsole_getavailable() ICODE_ATTR;
636
int dbgconsole_getavailable()
637
{
638
    int available = dbgconrecvwriteidx - dbgconrecvreadidx;
639
    if (available < 0) available += sizeof(dbgconrecvbuf);
640
    return available;
641
}
642
 
643
int dbgconsole_getc(int timeout)
644
{
645
    if (!dbgconsole_getavailable())
646
    {
647
        wakeup_wait(&dbgconrecvwakeup, TIMEOUT_NONE);
648
        if (!dbgconsole_getavailable())
649
        {
650
            wakeup_wait(&dbgconrecvwakeup, timeout);
651
            if (!dbgconsole_getavailable()) return -1;
652
        }
653
    }
654
    int byte = dbgconrecvbuf[dbgconrecvreadidx++];
655
    if (dbgconrecvreadidx >= sizeof(dbgconrecvbuf))
656
        dbgconrecvreadidx -= sizeof(dbgconrecvbuf);
657
    return byte;
658
}
659
 
660
int dbgconsole_read(char* buffer, size_t length, int timeout)
661
{
662
    if (!length) return 0;
663
    int available = dbgconsole_getavailable();
664
    if (!available)
665
    {
666
        wakeup_wait(&dbgconrecvwakeup, TIMEOUT_NONE);
667
        int available = dbgconsole_getavailable();
668
        if (!available)
669
        {
670
            wakeup_wait(&dbgconrecvwakeup, timeout);
671
            int available = dbgconsole_getavailable();
672
            if (!available) return 0;
673
        }
674
    }
675
    if (available > length) available = length;
676
    int left = available;
677
    if (dbgconrecvreadidx + available >= sizeof(dbgconrecvbuf))
678
    {
679
        int bytes = sizeof(dbgconrecvbuf) - dbgconrecvreadidx;
680
        memcpy(buffer, &dbgconrecvbuf[dbgconrecvreadidx], bytes);
681
        dbgconrecvreadidx = 0;
682
        buffer = &buffer[bytes];
683
        left -= bytes;
684
    }
685
    if (left) memcpy(buffer, &dbgconrecvbuf[dbgconrecvreadidx], left);
686
    dbgconrecvreadidx += left;
687
    return available;
688
}