Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
892 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
6
//    This file is part of emCORE.
7
//
8
//    emCORE 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
//    emCORE 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 emCORE.  If not, see <http://www.gnu.org/licenses/>.
20
//
21
//
22
 
23
 
24
#include "global.h"
25
#include "usbdebug.h"
26
#include "panic.h"
27
#include "usb.h"
28
#include "thread.h"
29
#include "console.h"
30
#include "util.h"
31
#include "contextswitch.h"
32
#include "power.h"
33
#include "mmu.h"
34
#include "shutdown.h"
35
#include "execimage.h"
36
#ifdef HAVE_I2C
37
#include "i2c.h"
38
#endif
39
#ifdef HAVE_BOOTFLASH
40
#include "bootflash.h"
41
#endif
42
#ifdef HAVE_HWKEYAES
43
#include "hwkeyaes.h"
44
#endif
45
#ifdef HAVE_HMACSHA1
46
#include "hmacsha1.h"
47
#endif
48
#ifdef USB_HAVE_TARGET_SPECIFIC_REQUESTS
49
#include "usbtarget.h"
50
#endif
51
#ifdef HAVE_STORAGE
52
#include "storage.h"
53
#include "disk.h"
54
#include "file.h"
55
#include "dir.h"
56
#include "libc/include/errno.h"
57
#endif
58
 
59
 
60
static uint32_t dbgbuf[16] CACHEALIGN_ATTR;
61
 
62
enum dbgstate_t
63
{
64
    DBGSTATE_IDLE = 0,
65
    DBGSTATE_SETUP,
66
    DBGSTATE_WRITE_MEM,
67
    DBGSTATE_ASYNC,
68
    DBGSTATE_RESPOND,
69
};
70
 
71
static struct scheduler_thread dbgthread_handle IBSS_ATTR;
72
static uint32_t dbgstack[0x200] STACK_ATTR;
73
struct wakeup dbgwakeup IBSS_ATTR;
74
static bool dbgenabled IBSS_ATTR;
75
static bool dbgbusy IBSS_ATTR;
76
static const struct usb_instance* dbgusb IBSS_ATTR;
77
static enum dbgstate_t dbgstate IBSS_ATTR;
78
static void* dbgmemaddr IBSS_ATTR;
79
static uint32_t dbgmemlen IBSS_ATTR;
80
static char dbgconsendbuf[4096];
81
static char dbgconrecvbuf[1024];
82
static int dbgconsendreadidx IBSS_ATTR;
83
static int dbgconsendwriteidx IBSS_ATTR;
84
static int dbgconrecvreadidx IBSS_ATTR;
85
static int dbgconrecvwriteidx IBSS_ATTR;
86
static struct wakeup dbgconsendwakeup IBSS_ATTR;
87
static struct wakeup dbgconrecvwakeup IBSS_ATTR;
88
static bool dbgconsoleattached IBSS_ATTR;
89
 
90
static const char dbgconoverflowstr[] = "\n\n[overflowed]\n\n";
91
 
92
extern int _poolstart;   // These aren't ints at all, but gcc complains about void types being
93
extern int _poolend;     // used here, and we only need the address, so just make it happy...
94
 
95
 
96
void reset() __attribute__((noreturn));
97
 
98
void usbdebug_enable(const struct usb_instance* data, int interface, int altsetting)
99
{
100
    dbgusb = data;
101
    dbgstate = DBGSTATE_IDLE;
102
    dbgenabled = true;
103
}
104
 
105
void usbdebug_disable(const struct usb_instance* data, int interface, int altsetting)
106
{
107
    dbgenabled = false;
108
    dbgstate = DBGSTATE_IDLE;
109
}
110
 
111
bool usbdebug_handle_data(const struct usb_instance* data, int bytesleft)
112
{
113
    uint32_t* buf = (uint32_t*)data->buffer->raw;
114
    usb_ep0_start_rx(dbgusb, 0, NULL);
115
    switch (dbgstate)
116
    {
117
    case DBGSTATE_SETUP:
118
        switch (buf[0])
119
        {
120
        case 1:  // GET INFO
121
            dbgbuf[0] = 1;
122
            switch (buf[1])
123
            {
124
            case 0:  // GET VERSION INFO
125
                dbgbuf[1] = VERSION_SVN_INT;
126
                dbgbuf[2] = VERSION_MAJOR | (VERSION_MINOR << 8) | (VERSION_PATCH << 16) | (2 << 24);
127
                dbgbuf[3] = PLATFORM_ID;
128
                break;
129
            case 1:  // GET USER MEMORY INFO
130
                dbgbuf[1] = (uint32_t)&_poolstart;
131
                dbgbuf[2] = (uint32_t)&_poolend;
132
                break;
133
            default:
134
                dbgbuf[0] = 2;
135
            }
136
            break;
137
        case 4:  // READ MEMORY
138
            dbgbuf[0] = 1;
139
            dbgmemaddr = (void*)buf[1];
140
            dbgmemlen = buf[2];
141
            break;
142
        case 5:  // WRITE MEMORY
143
        {
144
            dbgmemaddr = (void*)buf[1];
145
            dbgmemlen = buf[2];
146
            int len = MIN(48, dbgmemlen);
147
            dbgmemlen -= len;
148
            memcpy(dbgmemaddr, &buf[4], len);
149
            if (dbgmemlen)
150
            {
151
                dbgmemaddr += len;
152
                dbgstate = DBGSTATE_WRITE_MEM;
153
                usb_ep0_start_rx(dbgusb, 1, usbdebug_handle_data);
154
                return true;
155
            }
156
            dbgbuf[0] = 1;
157
            break;
158
        }
159
        case 10:  // READ CONSOLE
160
            dbgconsoleattached = true;
161
            int bytes = dbgconsendwriteidx - dbgconsendreadidx;
162
            int used = 0;
163
            if (bytes)
164
            {
165
                if (bytes < 0) bytes += sizeof(dbgconsendbuf);
166
                used = bytes;
167
                if (bytes > buf[1]) bytes = buf[1];
168
                int readbytes = bytes;
169
                char* outptr = (char*)&dbgbuf[4];
170
                if (dbgconsendreadidx + bytes >= sizeof(dbgconsendbuf))
171
                {
172
                    readbytes = sizeof(dbgconsendbuf) - dbgconsendreadidx;
173
                    memcpy(outptr, &dbgconsendbuf[dbgconsendreadidx], readbytes);
174
                    dbgconsendreadidx = 0;
175
                    outptr = &outptr[readbytes];
176
                    readbytes = bytes - readbytes;
177
                }
178
                if (readbytes) memcpy(outptr, &dbgconsendbuf[dbgconsendreadidx], readbytes);
179
                dbgconsendreadidx += readbytes;
180
                wakeup_signal(&dbgconsendwakeup);
181
            }
182
            dbgbuf[0] = 1;
183
            dbgbuf[1] = bytes;
184
            dbgbuf[2] = sizeof(dbgconsendbuf);
185
            dbgbuf[3] = used - bytes;
186
            break;
187
        case 11:  // WRITE CONSOLE
188
            bytes = dbgconrecvreadidx - dbgconrecvwriteidx - 1;
189
            if (bytes < 0) bytes += sizeof(dbgconrecvbuf);
190
            if (bytes)
191
            {
192
                if (bytes > buf[1]) bytes = buf[1];
193
                int writebytes = bytes;
194
                char* readptr = (char*)&buf[4];
195
                if (dbgconrecvwriteidx + bytes >= sizeof(dbgconrecvbuf))
196
                {
197
                    writebytes = sizeof(dbgconrecvbuf) - dbgconrecvwriteidx;
198
                    memcpy(&dbgconrecvbuf[dbgconrecvwriteidx], readptr, writebytes);
199
                    dbgconrecvwriteidx = 0;
200
                    readptr = &readptr[writebytes];
201
                    writebytes = bytes - writebytes;
202
                }
203
                if (writebytes) memcpy(&dbgconrecvbuf[dbgconrecvwriteidx], readptr, writebytes);
204
                dbgconrecvwriteidx += writebytes;
205
                wakeup_signal(&dbgconrecvwakeup);
206
            }
207
            dbgbuf[0] = 1;
208
            dbgbuf[1] = bytes;
209
            dbgbuf[2] = sizeof(dbgconrecvbuf);
210
            dbgbuf[3] = dbgconrecvreadidx - dbgconrecvwriteidx - 1;
211
            break;
212
        case 15:  // GET PROCESS INFO
213
            dbgbuf[0] = 1;
214
            dbgbuf[1] = SCHEDULER_THREAD_INFO_VERSION;
215
            dbgbuf[2] = (uint32_t)head_thread;
216
            break;
217
        case 16:  // FREEZE SCHEDULER
218
            dbgbuf[1] = scheduler_freeze(buf[1]);
219
            scheduler_switch(NULL, NULL);
220
            dbgbuf[0] = 1;
221
            break;
222
        case 17:  // SUSPEND THREAD
223
            if (buf[1])
224
            {
225
                if (thread_suspend((struct scheduler_thread*)(buf[2])) == ALREADY_SUSPENDED)
226
                    dbgbuf[1] = 1;
227
                else dbgbuf[1] = 0;
228
            }
229
            else
230
            {
231
                if (thread_resume((struct scheduler_thread*)(buf[2])) == ALREADY_RESUMED)
232
                    dbgbuf[1] = 0;
233
                else dbgbuf[1] = 1;
234
            }
235
            dbgbuf[0] = 1;
236
            break;
237
        case 18:  // KILL THREAD
238
            thread_terminate((struct scheduler_thread*)(buf[1]));
239
            dbgbuf[0] = 1;
240
            break;
241
        case 19:  // CREATE THREAD
242
            dbgbuf[0] = 1;
243
            dbgbuf[1] = (uint32_t)thread_create(NULL, (const char*)(buf[1]), (const void*)(buf[2]),
244
                                                (char*)(buf[3]), buf[4], (enum thread_type)buf[5],
245
                                                buf[6], buf[7], (void*)buf[8], (void*)buf[9],
246
                                                (void*)buf[10], (void*)buf[11]);
247
            break;
248
        case 20:  // FLUSH CACHE
249
            clean_dcache();
250
            invalidate_icache();
251
            buf[0] = 1;
252
            break;
253
        case 2:  // RESET
254
            if (!buf[1]) reset();
255
        default:
256
            if (!dbgbusy)
257
            {
258
                memcpy(dbgbuf, buf, 64);
259
                dbgstate = DBGSTATE_ASYNC;
260
                dbgbusy = 1;
261
                wakeup_signal(&dbgwakeup);
262
                return true;
263
            }
264
            buf[0] = 3;
265
            break;
266
        }
267
        break;
268
    case DBGSTATE_WRITE_MEM:
269
    {
270
        int len = MIN(64, dbgmemlen);
271
        dbgmemlen -= len;
272
        memcpy(dbgmemaddr, buf, len);
273
        if (dbgmemlen)
274
        {
275
            dbgmemaddr += len;
276
            usb_ep0_start_rx(dbgusb, 1, usbdebug_handle_data);
277
            return true;
278
        }
279
        dbgbuf[0] = 1;
280
        break;
281
    }
282
    default: break;
283
    }
284
    dbgstate = DBGSTATE_RESPOND;
285
    usb_ep0_start_tx(dbgusb, NULL, 0, true, NULL);
286
    return true;
287
}
288
 
289
int usbdebug_handle_setup(const struct usb_instance* data, int interface, union usb_ep0_buffer* request, const void** response)
290
{
291
    int size = -1;
292
    switch (request->setup.bmRequestType.type)
293
    {
294
    case USB_SETUP_BMREQUESTTYPE_TYPE_VENDOR:
295
        switch (request->setup.bRequest.raw)
296
        {
297
        case 0x00:
298
            switch (data->buffer->setup.bmRequestType.direction)
299
            {
300
            case USB_SETUP_BMREQUESTTYPE_DIRECTION_OUT:
301
                dbgstate = DBGSTATE_SETUP;
302
                dbgmemlen = 0;
303
                usb_ep0_start_rx(dbgusb, 1, usbdebug_handle_data);
304
                return -3;
305
            case USB_SETUP_BMREQUESTTYPE_DIRECTION_IN:
306
                switch (dbgstate)
307
                {
308
                case DBGSTATE_RESPOND:
309
                {
310
                    int len = MIN(48, dbgmemlen);
311
                    if (len) memcpy(&dbgbuf[4], dbgmemaddr, len);
312
                    dbgmemlen -= len;
313
                    if (dbgmemlen)
314
                    {
315
                        usb_ep0_start_rx(dbgusb, 0, NULL);
316
                        data->state->ep0_tx_ptr = dbgmemaddr - 16;
317
                        data->state->ep0_tx_len = dbgmemlen;
318
                        usb_ep0_start_tx(dbgusb, dbgbuf, len + 16, !data->state->ep0_tx_len, usb_ep0_tx_callback);
319
                        return -3;
320
                    }
321
                    dbgstate = DBGSTATE_IDLE;
322
                    *response = dbgbuf;
323
                    return len + 16;
324
                }
325
                default: return -2;
326
                }
327
                break;
328
            }
329
            break;
330
        default: break;
331
        }
332
        break;
333
        default: break;
334
    }
335
    return size;
336
}
337
 
338
void dbgthread(void* arg0, void* arg1, void* arg2, void* arg3)
339
{
340
    struct scheduler_thread* t;
341
    while (1)
342
    {
343
        wakeup_wait(&dbgwakeup, TIMEOUT_BLOCK);
344
        for (t = head_thread; t; t = t->thread_next)
345
            if (t->state == THREAD_DEFUNCT)
346
            {
347
                if (t->block_type == THREAD_DEFUNCT_STKOV)
348
                {
349
                    if (t->name) cprintf(1, "\n*PANIC*\nStack overflow! (%s)\n", t->name);
350
                    else cprintf(1, "\n*PANIC*\nStack overflow! (%08X)\n", t);
351
                }
352
                t->state = THREAD_DEFUNCT_ACK;
353
            }
354
        uint32_t mode = enter_critical_section();
355
        uint32_t buf[16];
356
        if (dbgstate == DBGSTATE_ASYNC)
357
        {
358
            memcpy(buf, dbgbuf, 64);
359
            leave_critical_section(mode);
360
            void* addr = &buf[4];
361
            int len = 0;
362
            switch (buf[0])
363
            {
364
                case 2:  // RESET
365
                    shutdown(false);
366
                    reset();
367
                case 3:  // POWER OFF
368
                    if (buf[1]) shutdown(true);
369
                    power_off();
370
                    buf[0] = 1;
371
                    break;
372
#ifdef HAVE_I2C
373
                case 8:  // READ I2C
374
                    len = buf[1] >> 24;
375
                    i2c_recv(buf[1] & 0xff, (buf[1] >> 8) & 0xff, (buf[1] >> 16) & 0xff,
376
                             (uint8_t*)&buf[4], len);
377
                    buf[0] = 1;
378
                    break;
379
                case 9:  // WRITE I2C
380
                    i2c_send(buf[1] & 0xff, (buf[1] >> 8) & 0xff, (buf[1] >> 16) & 0xff,
381
                             (uint8_t*)&buf[4], buf[1] >> 24);
382
                    buf[0] = 1;
383
                    break;
384
#endif
385
                case 12:  // CWRITE
386
                    cwrite(buf[1], (const char*)&buf[4], buf[2]);
387
                    buf[0] = 1;
388
                    break;
389
                case 13:  // CREAD
390
                    buf[0] = 1;
391
                    buf[1] = cread(buf[1], (char*)&buf[4], buf[2], 0);
392
                    break;
393
                case 14:  // CFLUSH
394
                    cflush(buf[1]);
395
                    buf[0] = 1;
396
                    break;
397
                case 21:  // EXECIMAGE
398
                {
399
                    int argc = buf[2] >> 24;
400
                    if (!buf[3])
401
                    {
402
                        buf[3] = (uint32_t)&buf[4];
403
                        int i;
404
                        for (i = 0; i < argc; i++) buf[i + 4] += buf[3];
405
                    }
406
                    buf[0] = 1;
407
                    buf[1] = (uint32_t)execimage((void*)buf[1], buf[2] & 0x10000, argc, (const char* const*)buf[3]);
408
                    break;
409
                }
410
#ifdef HAVE_BOOTFLASH
411
                case 22:  // READ BOOT FLASH
412
                    bootflash_readraw((void*)buf[1], buf[2], buf[3]);
413
                    buf[0] = 1;
414
                    break;
415
                case 23:  // WRITE BOOT FLASH
416
                    bootflash_writeraw((void*)buf[1], buf[2], buf[3]);
417
                    buf[0] = 1;
418
                    break;
419
#endif
420
                case 24:  // EXECFIRMWARE
421
                    shutdown(false);
422
                    execfirmware((void*)buf[1], (void*)buf[2], (size_t)buf[3]);
423
                    buf[0] = 1;
424
                    break;
425
#ifdef HAVE_HWKEYAES
426
                case 25:  // HWKEYAES
427
                    hwkeyaes((enum hwkeyaes_direction)((uint8_t*)buf)[4], ((uint16_t*)buf)[3], (void*)buf[2], buf[3]);
428
                    buf[0] = 1;
429
                    break;
430
#endif
431
#ifdef HAVE_HMACSHA1
432
                case 26:  // HMACSHA1
433
                    hmacsha1((void*)buf[1], buf[2], (void*)buf[3]);
434
                    buf[0] = 1;
435
                    break;
436
#endif
437
#ifdef HAVE_STORAGE
438
                case 27:  // STORAGE_GET_INFO
439
                    buf[0] = 1;
440
                    storage_get_info(buf[1], (struct storage_info*)&buf[4]);
441
                    buf[1] = 1;
442
                    break;
443
                case 28:  // STORAGE_READ_SECTORS_MD
444
                    buf[0] = 1;
445
                    buf[1] = (uint32_t)storage_read_sectors_md(buf[1], buf[2] | (((uint64_t)(buf[3]) << 32)),
446
                                                               buf[4], (void*)(buf[5]));
447
                    break;
448
                case 29:  // STORAGE_WRITE_SECTORS_MD
449
                    buf[0] = 1;
450
                    buf[1] = (uint32_t)storage_write_sectors_md(buf[1], buf[2] | (((uint64_t)(buf[3]) << 32)),
451
                                                                buf[4], (void*)(buf[5]));
452
                    break;
453
                case 30:  // FILE_OPEN
454
                {
455
                    buf[0] = 1;
456
                    if (!buf[3]) buf[3] = (uint32_t)&buf[4];
457
                    int fd = file_open((char*)buf[3], (int)buf[1]);
458
                    if (fd > 0) reown_file(fd, KERNEL_OWNER(KERNEL_OWNER_USB_MONITOR));
459
                    buf[1] = (uint32_t)fd;
460
                    break;
461
                }
462
                case 31:  // FILESIZE
463
                    buf[0] = 1;
464
                    buf[1] = (uint32_t)filesize((int)buf[1]);
465
                    break;
466
                case 32:  // READ
467
                    buf[0] = 1;
468
                    buf[1] = (uint32_t)read((int)buf[1], (void*)buf[2], (size_t)buf[3]);
469
                    break;
470
                case 33:  // WRITE
471
                    buf[0] = 1;
472
                    buf[1] = (uint32_t)write((int)buf[1], (void*)buf[2], (size_t)buf[3]);
473
                    break;
474
                case 34:  // LSEEK
475
                    buf[0] = 1;
476
                    buf[1] = (uint32_t)lseek((int)buf[1], (off_t)buf[2], (int)buf[3]);
477
                    break;
478
                case 35:  // FTRUNCATE
479
                    buf[0] = 1;
480
                    buf[1] = (uint32_t)ftruncate((int)buf[1], (off_t)buf[2]);
481
                    break;
482
                case 36:  // FSYNC
483
                    buf[0] = 1;
484
                    buf[1] = (uint32_t)fsync((int)buf[1]);
485
                    break;
486
                case 37:  // CLOSE
487
                    buf[0] = 1;
488
                    buf[1] = (uint32_t)close((int)buf[1]);
489
                    break;
490
                case 38:  // CLOSE_MONITOR_FILES
491
                    buf[0] = 1;
492
                    buf[1] = (uint32_t)close_all_of_process(KERNEL_OWNER(KERNEL_OWNER_USB_MONITOR));
493
                    break;
494
                case 39:  // RELEASE_FILES
495
                    buf[0] = 1;
496
                    buf[1] = (uint32_t)release_files((int)buf[1]);
497
                    break;
498
                case 40:  // REMOVE
499
                    buf[0] = 1;
500
                    if (!buf[3]) buf[3] = (uint32_t)&buf[4];
501
                    buf[1] = (uint32_t)remove((char*)buf[3]);
502
                    break;
503
                case 41:  // RENAME
504
                    buf[0] = 1;
505
                    buf[1] = (uint32_t)rename((char*)buf[2], (char*)buf[3]);
506
                    break;
507
                case 42:  // OPENDIR
508
                {
509
                    buf[0] = 1;
510
                    if (!buf[3]) buf[3] = (uint32_t)&buf[4];
511
                    DIR* dir = opendir((char*)buf[3]);
512
                    if (dir > 0) reown_dir(dir, KERNEL_OWNER(KERNEL_OWNER_USB_MONITOR));
513
                    buf[1] = (uint32_t)dir;
514
                    break;
515
                }
516
                case 43:  // READDIR
517
                    buf[0] = 1;
518
                    buf[3] = (uint32_t)readdir((DIR*)buf[1]);
519
                    buf[1] = 1;
520
                    buf[2] = MAX_PATH;
521
                    break;
522
                case 44:  // CLOSEDIR
523
                    buf[0] = 1;
524
                    buf[1] = (uint32_t)closedir((DIR*)buf[1]);
525
                    break;
526
                case 45:  // CLOSE_MONITOR_DIRS
527
                    buf[0] = 1;
528
                    buf[1] = (uint32_t)closedir_all_of_process(KERNEL_OWNER(KERNEL_OWNER_USB_MONITOR));
529
                    break;
530
                case 46:  // RELEASE_DIRS
531
                    buf[0] = 1;
532
                    buf[1] = (uint32_t)release_dirs((int)buf[1]);
533
                    break;
534
                case 47:  // MKDIR
535
                    buf[0] = 1;
536
                    if (!buf[3]) buf[3] = (uint32_t)&buf[4];
537
                    buf[1] = (uint32_t)mkdir((char*)buf[3]);
538
                    break;
539
                case 48:  // RMDIR
540
                    buf[0] = 1;
541
                    if (!buf[3]) buf[3] = (uint32_t)&buf[4];
542
                    buf[1] = (uint32_t)rmdir((char*)buf[3]);
543
                    break;
544
                case 49:  // ERRNO
545
                    buf[0] = 1;
546
                    buf[1] = (uint32_t)errno;
547
                    break;
548
#ifdef HAVE_HOTSWAP
549
                case 50:  // DISK_MOUNT
550
                    buf[0] = 1;
551
                    buf[1] = (uint32_t)disk_mount((int)buf[1]);
552
                    break;
553
                case 51:  // DISK_UNMOUNT
554
                    buf[0] = 1;
555
                    buf[1] = (uint32_t)disk_unmount((int)buf[1]);
556
                    break;
557
#endif
558
                case 58:  // FAT_ENABLE_FLUSHING
559
                    buf[0] = 1;
560
                    fat_enable_flushing((bool)buf[1]);
561
                    break;
562
                case 59:  // FAT_SIZE
563
                    buf[0] = 1;
564
                    fat_size_mv(buf[1], &buf[1], &buf[2]);
565
                    break;
566
#endif
567
                case 52:  // MALLOC
568
                    buf[0] = 1;
569
                    buf[1] = (uint32_t)malloc((size_t)buf[1]);
570
                    if (buf[1]) reownalloc(buf[1], KERNEL_OWNER(KERNEL_OWNER_USB_MONITOR));
571
                    break;
572
                case 53:  // MEMALIGN
573
                    buf[0] = 1;
574
                    buf[1] = (uint32_t)memalign((size_t)buf[1], (size_t)buf[2]);
575
                    if (buf[1]) reownalloc(buf[1], KERNEL_OWNER(KERNEL_OWNER_USB_MONITOR));
576
                    break;
577
                case 54:  // REALLOC
578
                    buf[0] = 1;
579
                    buf[1] = (uint32_t)realloc((void*)buf[1], (size_t)buf[2]);
580
                    break;
581
                case 55:  // REOWNALLOC
582
                    buf[0] = 1;
583
                    reownalloc((void*)buf[1], (void*)buf[2]);
584
                    break;
585
                case 56:  // FREE
586
                    buf[0] = 1;
587
                    free((void*)buf[1]);
588
                    break;
589
                case 57:  // FREE MONITOR ALLOCATIONS
590
                    buf[0] = 1;
591
                    buf[1] = (uint32_t)free_all_of_thread(KERNEL_OWNER(KERNEL_OWNER_USB_MONITOR));
592
                    break;
593
#ifdef HAVE_RTC
594
                case 60:  // RTC READ
595
                    buf[0] = 1;
596
                    rtc_read_datetime((struct rtc_datetime*)&buf[1]);
597
                    break;
598
                case 61:  // RTC WRITE
599
                    buf[0] = 1;
600
                    rtc_write_datetime((const struct rtc_datetime*)&buf[1]);
601
                    break;
602
#endif
603
#ifdef USB_HAVE_TARGET_SPECIFIC_REQUESTS
604
                if (buf[0] >= 0xffff0000)
605
                    len = usb_target_handle_request(buf, sizeof(buf), &addr);
606
                    break;
607
#endif
608
                default:
609
                    buf[0] = 2;
610
                    break;
611
            }
612
            mode = enter_critical_section();
613
            if (dbgstate == DBGSTATE_ASYNC)
614
            {
615
                usb_ep0_start_tx(dbgusb, NULL, 0, true, NULL);
616
                dbgstate = DBGSTATE_RESPOND;
617
                dbgmemaddr = addr;
618
                dbgmemlen = len;
619
                memcpy(dbgbuf, buf, 64);
620
            }
621
        }
622
        dbgbusy = false;
623
        leave_critical_section(mode);
624
    }
625
}
626
 
627
void usbdebug_init(void)
628
{
629
    wakeup_init(&dbgwakeup);
630
    dbgconsendreadidx = 0;
631
    dbgconsendwriteidx = 0;
632
    dbgconrecvreadidx = 0;
633
    dbgconrecvwriteidx = 0;
634
    wakeup_init(&dbgconsendwakeup);
635
    wakeup_init(&dbgconrecvwakeup);
636
    dbgenabled = false;
637
    dbgbusy = false;
638
    dbgstate = DBGSTATE_IDLE;
639
    dbgconsoleattached = false;
640
    thread_create(&dbgthread_handle, "monitor worker", dbgthread, dbgstack,
641
                  sizeof(dbgstack), CORE_THREAD, 255, true, NULL, NULL, NULL, NULL);
642
}
643
 
644
int dbgconsole_getfree() ICODE_ATTR;
645
int dbgconsole_getfree()
646
{
647
    int free = dbgconsendreadidx - dbgconsendwriteidx - 1;
648
    if (free < 0) free += sizeof(dbgconsendbuf);
649
    return free;
650
}
651
 
652
int dbgconsole_makespace(int length, bool safe) ICODE_ATTR;
653
int dbgconsole_makespace(int length, bool safe)
654
{
655
    int free = dbgconsole_getfree();
656
    while (!free && dbgconsoleattached && !safe)
657
    {
658
        dbgconsoleattached = false;
659
        wakeup_wait(&dbgconsendwakeup, 2000000);
660
        free = dbgconsole_getfree();
661
    }
662
    if (free) return free > length ? length : free;
663
    if (length > sizeof(dbgconsendbuf) - 17) length = sizeof(dbgconsendbuf) - 17;
664
    uint32_t mode = enter_critical_section();
665
    dbgconsendreadidx += length;
666
    if (dbgconsendreadidx >= sizeof(dbgconsendbuf))
667
        dbgconsendreadidx -= sizeof(dbgconsendbuf);
668
    int offset = 0;
669
    int idx = dbgconsendreadidx;
670
    if (idx + 16 >= sizeof(dbgconsendbuf))
671
    {
672
        offset = sizeof(dbgconsendbuf) - dbgconsendreadidx;
673
        memcpy(&dbgconsendbuf[dbgconsendreadidx], dbgconoverflowstr, offset);
674
        idx = 0;
675
    }
676
    if (offset != 16) memcpy(&dbgconsendbuf[idx], &dbgconoverflowstr[offset], 16 - offset);
677
    leave_critical_section(mode);
678
    return length;
679
}
680
 
681
void dbgconsole_putc_internal(char string, bool safe)
682
{
683
    dbgconsole_makespace(1, safe);
684
    dbgconsendbuf[dbgconsendwriteidx++] = string;
685
    if (dbgconsendwriteidx >= sizeof(dbgconsendbuf))
686
        dbgconsendwriteidx -= sizeof(dbgconsendbuf);
687
}
688
 
689
void dbgconsole_putc(char string)
690
{
691
    dbgconsole_putc_internal(string, false);
692
}
693
 
694
void dbgconsole_sputc(char string)
695
{
696
    dbgconsole_putc_internal(string, true);
697
}
698
 
699
void dbgconsole_write_internal(const char* string, size_t length, bool safe)
700
{
701
    while (length)
702
    {
703
        int space = dbgconsole_makespace(length, safe);
704
        if (dbgconsendwriteidx + space >= sizeof(dbgconsendbuf))
705
        {
706
            int bytes = sizeof(dbgconsendbuf) - dbgconsendwriteidx;
707
            memcpy(&dbgconsendbuf[dbgconsendwriteidx], string, bytes);
708
            dbgconsendwriteidx = 0;
709
            string = &string[bytes];
710
            space -= bytes;
711
            length -= bytes;
712
        }
713
        if (space) memcpy(&dbgconsendbuf[dbgconsendwriteidx], string, space);
714
        dbgconsendwriteidx += space;
715
        string = &string[space];
716
        length -= space;
717
    }
718
}
719
 
720
void dbgconsole_write(const char* string, size_t length)
721
{
722
    dbgconsole_write_internal(string, length, false);
723
}
724
 
725
void dbgconsole_swrite(const char* string, size_t length)
726
{
727
    dbgconsole_write_internal(string, length, true);
728
}
729
 
730
void dbgconsole_puts(const char* string)
731
{
732
    dbgconsole_write(string, strlen(string));
733
}
734
 
735
void dbgconsole_sputs(const char* string)
736
{
737
    dbgconsole_swrite(string, strlen(string));
738
}
739
 
740
int dbgconsole_getavailable() ICODE_ATTR;
741
int dbgconsole_getavailable()
742
{
743
    int available = dbgconrecvwriteidx - dbgconrecvreadidx;
744
    if (available < 0) available += sizeof(dbgconrecvbuf);
745
    return available;
746
}
747
 
748
int dbgconsole_getc(int timeout)
749
{
750
    if (!dbgconsole_getavailable())
751
    {
752
        wakeup_wait(&dbgconrecvwakeup, TIMEOUT_NONE);
753
        if (!dbgconsole_getavailable())
754
        {
755
            wakeup_wait(&dbgconrecvwakeup, timeout);
756
            if (!dbgconsole_getavailable()) return -1;
757
        }
758
    }
759
    int byte = dbgconrecvbuf[dbgconrecvreadidx++];
760
    if (dbgconrecvreadidx >= sizeof(dbgconrecvbuf))
761
        dbgconrecvreadidx -= sizeof(dbgconrecvbuf);
762
    return byte;
763
}
764
 
765
int dbgconsole_read(char* buffer, size_t length, int timeout)
766
{
767
    if (!length) return 0;
768
    int available = dbgconsole_getavailable();
769
    if (!available)
770
    {
771
        wakeup_wait(&dbgconrecvwakeup, TIMEOUT_NONE);
772
        int available = dbgconsole_getavailable();
773
        if (!available)
774
        {
775
            wakeup_wait(&dbgconrecvwakeup, timeout);
776
            int available = dbgconsole_getavailable();
777
            if (!available) return 0;
778
        }
779
    }
780
    if (available > length) available = length;
781
    int left = available;
782
    if (dbgconrecvreadidx + available >= sizeof(dbgconrecvbuf))
783
    {
784
        int bytes = sizeof(dbgconrecvbuf) - dbgconrecvreadidx;
785
        memcpy(buffer, &dbgconrecvbuf[dbgconrecvreadidx], bytes);
786
        dbgconrecvreadidx = 0;
787
        buffer = &buffer[bytes];
788
        left -= bytes;
789
    }
790
    if (left) memcpy(buffer, &dbgconrecvbuf[dbgconrecvreadidx], left);
791
    dbgconrecvreadidx += left;
792
    return available;
793
}
794