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