~vcs-imports/qemu/git

« back to all changes in this revision

Viewing changes to hw/usb-msd.c

  • Committer: bellard
  • Date: 2003-03-23 20:17:16 UTC
  • Revision ID: git-v1:3ef693a03205217a5def9318b443c8cb6de17217
distribution patches


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@44 c046a42c-6fe2-441c-8c8c-71466251a162

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * USB Mass Storage Device emulation
3
 
 *
4
 
 * Copyright (c) 2006 CodeSourcery.
5
 
 * Written by Paul Brook
6
 
 *
7
 
 * This code is licenced under the LGPL.
8
 
 */
9
 
 
10
 
#include "qemu-common.h"
11
 
#include "usb.h"
12
 
#include "block.h"
13
 
#include "scsi-disk.h"
14
 
 
15
 
//#define DEBUG_MSD
16
 
 
17
 
#ifdef DEBUG_MSD
18
 
#define DPRINTF(fmt, args...) \
19
 
do { printf("usb-msd: " fmt , ##args); } while (0)
20
 
#else
21
 
#define DPRINTF(fmt, args...) do {} while(0)
22
 
#endif
23
 
 
24
 
/* USB requests.  */
25
 
#define MassStorageReset  0xff
26
 
#define GetMaxLun         0xfe
27
 
 
28
 
enum USBMSDMode {
29
 
    USB_MSDM_CBW, /* Command Block.  */
30
 
    USB_MSDM_DATAOUT, /* Tranfer data to device.  */
31
 
    USB_MSDM_DATAIN, /* Transfer data from device.  */
32
 
    USB_MSDM_CSW /* Command Status.  */
33
 
};
34
 
 
35
 
typedef struct {
36
 
    USBDevice dev;
37
 
    enum USBMSDMode mode;
38
 
    uint32_t scsi_len;
39
 
    uint8_t *scsi_buf;
40
 
    uint32_t usb_len;
41
 
    uint8_t *usb_buf;
42
 
    uint32_t data_len;
43
 
    uint32_t residue;
44
 
    uint32_t tag;
45
 
    BlockDriverState *bs;
46
 
    SCSIDevice *scsi_dev;
47
 
    int result;
48
 
    /* For async completion.  */
49
 
    USBPacket *packet;
50
 
} MSDState;
51
 
 
52
 
struct usb_msd_cbw {
53
 
    uint32_t sig;
54
 
    uint32_t tag;
55
 
    uint32_t data_len;
56
 
    uint8_t flags;
57
 
    uint8_t lun;
58
 
    uint8_t cmd_len;
59
 
    uint8_t cmd[16];
60
 
};
61
 
 
62
 
struct usb_msd_csw {
63
 
    uint32_t sig;
64
 
    uint32_t tag;
65
 
    uint32_t residue;
66
 
    uint8_t status;
67
 
};
68
 
 
69
 
static const uint8_t qemu_msd_dev_descriptor[] = {
70
 
        0x12,       /*  u8 bLength; */
71
 
        0x01,       /*  u8 bDescriptorType; Device */
72
 
        0x00, 0x01, /*  u16 bcdUSB; v1.0 */
73
 
 
74
 
        0x00,       /*  u8  bDeviceClass; */
75
 
        0x00,       /*  u8  bDeviceSubClass; */
76
 
        0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
77
 
        0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
78
 
 
79
 
        /* Vendor and product id are arbitrary.  */
80
 
        0x00, 0x00, /*  u16 idVendor; */
81
 
        0x00, 0x00, /*  u16 idProduct; */
82
 
        0x00, 0x00, /*  u16 bcdDevice */
83
 
 
84
 
        0x01,       /*  u8  iManufacturer; */
85
 
        0x02,       /*  u8  iProduct; */
86
 
        0x03,       /*  u8  iSerialNumber; */
87
 
        0x01        /*  u8  bNumConfigurations; */
88
 
};
89
 
 
90
 
static const uint8_t qemu_msd_config_descriptor[] = {
91
 
 
92
 
        /* one configuration */
93
 
        0x09,       /*  u8  bLength; */
94
 
        0x02,       /*  u8  bDescriptorType; Configuration */
95
 
        0x20, 0x00, /*  u16 wTotalLength; */
96
 
        0x01,       /*  u8  bNumInterfaces; (1) */
97
 
        0x01,       /*  u8  bConfigurationValue; */
98
 
        0x00,       /*  u8  iConfiguration; */
99
 
        0xc0,       /*  u8  bmAttributes;
100
 
                                 Bit 7: must be set,
101
 
                                     6: Self-powered,
102
 
                                     5: Remote wakeup,
103
 
                                     4..0: resvd */
104
 
        0x00,       /*  u8  MaxPower; */
105
 
 
106
 
        /* one interface */
107
 
        0x09,       /*  u8  if_bLength; */
108
 
        0x04,       /*  u8  if_bDescriptorType; Interface */
109
 
        0x00,       /*  u8  if_bInterfaceNumber; */
110
 
        0x00,       /*  u8  if_bAlternateSetting; */
111
 
        0x02,       /*  u8  if_bNumEndpoints; */
112
 
        0x08,       /*  u8  if_bInterfaceClass; MASS STORAGE */
113
 
        0x06,       /*  u8  if_bInterfaceSubClass; SCSI */
114
 
        0x50,       /*  u8  if_bInterfaceProtocol; Bulk Only */
115
 
        0x00,       /*  u8  if_iInterface; */
116
 
 
117
 
        /* Bulk-In endpoint */
118
 
        0x07,       /*  u8  ep_bLength; */
119
 
        0x05,       /*  u8  ep_bDescriptorType; Endpoint */
120
 
        0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
121
 
        0x02,       /*  u8  ep_bmAttributes; Bulk */
122
 
        0x40, 0x00, /*  u16 ep_wMaxPacketSize; */
123
 
        0x00,       /*  u8  ep_bInterval; */
124
 
 
125
 
        /* Bulk-Out endpoint */
126
 
        0x07,       /*  u8  ep_bLength; */
127
 
        0x05,       /*  u8  ep_bDescriptorType; Endpoint */
128
 
        0x02,       /*  u8  ep_bEndpointAddress; OUT Endpoint 2 */
129
 
        0x02,       /*  u8  ep_bmAttributes; Bulk */
130
 
        0x40, 0x00, /*  u16 ep_wMaxPacketSize; */
131
 
        0x00        /*  u8  ep_bInterval; */
132
 
};
133
 
 
134
 
static void usb_msd_copy_data(MSDState *s)
135
 
{
136
 
    uint32_t len;
137
 
    len = s->usb_len;
138
 
    if (len > s->scsi_len)
139
 
        len = s->scsi_len;
140
 
    if (s->mode == USB_MSDM_DATAIN) {
141
 
        memcpy(s->usb_buf, s->scsi_buf, len);
142
 
    } else {
143
 
        memcpy(s->scsi_buf, s->usb_buf, len);
144
 
    }
145
 
    s->usb_len -= len;
146
 
    s->scsi_len -= len;
147
 
    s->usb_buf += len;
148
 
    s->scsi_buf += len;
149
 
    s->data_len -= len;
150
 
    if (s->scsi_len == 0) {
151
 
        if (s->mode == USB_MSDM_DATAIN) {
152
 
            s->scsi_dev->read_data(s->scsi_dev, s->tag);
153
 
        } else if (s->mode == USB_MSDM_DATAOUT) {
154
 
            s->scsi_dev->write_data(s->scsi_dev, s->tag);
155
 
        }
156
 
    }
157
 
}
158
 
 
159
 
static void usb_msd_send_status(MSDState *s)
160
 
{
161
 
    struct usb_msd_csw csw;
162
 
 
163
 
    csw.sig = cpu_to_le32(0x53425355);
164
 
    csw.tag = cpu_to_le32(s->tag);
165
 
    csw.residue = s->residue;
166
 
    csw.status = s->result;
167
 
    memcpy(s->usb_buf, &csw, 13);
168
 
}
169
 
 
170
 
static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag,
171
 
                                     uint32_t arg)
172
 
{
173
 
    MSDState *s = (MSDState *)opaque;
174
 
    USBPacket *p = s->packet;
175
 
 
176
 
    if (tag != s->tag) {
177
 
        fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", tag);
178
 
    }
179
 
    if (reason == SCSI_REASON_DONE) {
180
 
        DPRINTF("Command complete %d\n", arg);
181
 
        s->residue = s->data_len;
182
 
        s->result = arg != 0;
183
 
        if (s->packet) {
184
 
            if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
185
 
                /* A deferred packet with no write data remaining must be
186
 
                   the status read packet.  */
187
 
                usb_msd_send_status(s);
188
 
                s->mode = USB_MSDM_CBW;
189
 
            } else {
190
 
                if (s->data_len) {
191
 
                    s->data_len -= s->usb_len;
192
 
                    if (s->mode == USB_MSDM_DATAIN)
193
 
                        memset(s->usb_buf, 0, s->usb_len);
194
 
                    s->usb_len = 0;
195
 
                }
196
 
                if (s->data_len == 0)
197
 
                    s->mode = USB_MSDM_CSW;
198
 
            }
199
 
            s->packet = NULL;
200
 
            usb_packet_complete(p);
201
 
        } else if (s->data_len == 0) {
202
 
            s->mode = USB_MSDM_CSW;
203
 
        }
204
 
        return;
205
 
    }
206
 
    s->scsi_len = arg;
207
 
    s->scsi_buf = s->scsi_dev->get_buf(s->scsi_dev, tag);
208
 
    if (p) {
209
 
        usb_msd_copy_data(s);
210
 
        if (s->usb_len == 0) {
211
 
            /* Set s->packet to NULL before calling usb_packet_complete
212
 
               because annother request may be issued before
213
 
               usb_packet_complete returns.  */
214
 
            DPRINTF("Packet complete %p\n", p);
215
 
            s->packet = NULL;
216
 
            usb_packet_complete(p);
217
 
        }
218
 
    }
219
 
}
220
 
 
221
 
static void usb_msd_handle_reset(USBDevice *dev)
222
 
{
223
 
    MSDState *s = (MSDState *)dev;
224
 
 
225
 
    DPRINTF("Reset\n");
226
 
    s->mode = USB_MSDM_CBW;
227
 
}
228
 
 
229
 
static int usb_msd_handle_control(USBDevice *dev, int request, int value,
230
 
                                  int index, int length, uint8_t *data)
231
 
{
232
 
    MSDState *s = (MSDState *)dev;
233
 
    int ret = 0;
234
 
 
235
 
    switch (request) {
236
 
    case DeviceRequest | USB_REQ_GET_STATUS:
237
 
        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
238
 
            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
239
 
        data[1] = 0x00;
240
 
        ret = 2;
241
 
        break;
242
 
    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
243
 
        if (value == USB_DEVICE_REMOTE_WAKEUP) {
244
 
            dev->remote_wakeup = 0;
245
 
        } else {
246
 
            goto fail;
247
 
        }
248
 
        ret = 0;
249
 
        break;
250
 
    case DeviceOutRequest | USB_REQ_SET_FEATURE:
251
 
        if (value == USB_DEVICE_REMOTE_WAKEUP) {
252
 
            dev->remote_wakeup = 1;
253
 
        } else {
254
 
            goto fail;
255
 
        }
256
 
        ret = 0;
257
 
        break;
258
 
    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
259
 
        dev->addr = value;
260
 
        ret = 0;
261
 
        break;
262
 
    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
263
 
        switch(value >> 8) {
264
 
        case USB_DT_DEVICE:
265
 
            memcpy(data, qemu_msd_dev_descriptor,
266
 
                   sizeof(qemu_msd_dev_descriptor));
267
 
            ret = sizeof(qemu_msd_dev_descriptor);
268
 
            break;
269
 
        case USB_DT_CONFIG:
270
 
            memcpy(data, qemu_msd_config_descriptor,
271
 
                   sizeof(qemu_msd_config_descriptor));
272
 
            ret = sizeof(qemu_msd_config_descriptor);
273
 
            break;
274
 
        case USB_DT_STRING:
275
 
            switch(value & 0xff) {
276
 
            case 0:
277
 
                /* language ids */
278
 
                data[0] = 4;
279
 
                data[1] = 3;
280
 
                data[2] = 0x09;
281
 
                data[3] = 0x04;
282
 
                ret = 4;
283
 
                break;
284
 
            case 1:
285
 
                /* vendor description */
286
 
                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
287
 
                break;
288
 
            case 2:
289
 
                /* product description */
290
 
                ret = set_usb_string(data, "QEMU USB HARDDRIVE");
291
 
                break;
292
 
            case 3:
293
 
                /* serial number */
294
 
                ret = set_usb_string(data, "1");
295
 
                break;
296
 
            default:
297
 
                goto fail;
298
 
            }
299
 
            break;
300
 
        default:
301
 
            goto fail;
302
 
        }
303
 
        break;
304
 
    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
305
 
        data[0] = 1;
306
 
        ret = 1;
307
 
        break;
308
 
    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
309
 
        ret = 0;
310
 
        break;
311
 
    case DeviceRequest | USB_REQ_GET_INTERFACE:
312
 
        data[0] = 0;
313
 
        ret = 1;
314
 
        break;
315
 
    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
316
 
        ret = 0;
317
 
        break;
318
 
    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
319
 
        if (value == 0 && index != 0x81) { /* clear ep halt */
320
 
            goto fail;
321
 
        }
322
 
        ret = 0;
323
 
        break;
324
 
        /* Class specific requests.  */
325
 
    case MassStorageReset:
326
 
        /* Reset state ready for the next CBW.  */
327
 
        s->mode = USB_MSDM_CBW;
328
 
        ret = 0;
329
 
        break;
330
 
    case GetMaxLun:
331
 
        data[0] = 0;
332
 
        ret = 1;
333
 
        break;
334
 
    default:
335
 
    fail:
336
 
        ret = USB_RET_STALL;
337
 
        break;
338
 
    }
339
 
    return ret;
340
 
}
341
 
 
342
 
static void usb_msd_cancel_io(USBPacket *p, void *opaque)
343
 
{
344
 
    MSDState *s = opaque;
345
 
    s->scsi_dev->cancel_io(s->scsi_dev, s->tag);
346
 
    s->packet = NULL;
347
 
    s->scsi_len = 0;
348
 
}
349
 
 
350
 
static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
351
 
{
352
 
    MSDState *s = (MSDState *)dev;
353
 
    int ret = 0;
354
 
    struct usb_msd_cbw cbw;
355
 
    uint8_t devep = p->devep;
356
 
    uint8_t *data = p->data;
357
 
    int len = p->len;
358
 
 
359
 
    switch (p->pid) {
360
 
    case USB_TOKEN_OUT:
361
 
        if (devep != 2)
362
 
            goto fail;
363
 
 
364
 
        switch (s->mode) {
365
 
        case USB_MSDM_CBW:
366
 
            if (len != 31) {
367
 
                fprintf(stderr, "usb-msd: Bad CBW size");
368
 
                goto fail;
369
 
            }
370
 
            memcpy(&cbw, data, 31);
371
 
            if (le32_to_cpu(cbw.sig) != 0x43425355) {
372
 
                fprintf(stderr, "usb-msd: Bad signature %08x\n",
373
 
                        le32_to_cpu(cbw.sig));
374
 
                goto fail;
375
 
            }
376
 
            DPRINTF("Command on LUN %d\n", cbw.lun);
377
 
            if (cbw.lun != 0) {
378
 
                fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
379
 
                goto fail;
380
 
            }
381
 
            s->tag = le32_to_cpu(cbw.tag);
382
 
            s->data_len = le32_to_cpu(cbw.data_len);
383
 
            if (s->data_len == 0) {
384
 
                s->mode = USB_MSDM_CSW;
385
 
            } else if (cbw.flags & 0x80) {
386
 
                s->mode = USB_MSDM_DATAIN;
387
 
            } else {
388
 
                s->mode = USB_MSDM_DATAOUT;
389
 
            }
390
 
            DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
391
 
                    s->tag, cbw.flags, cbw.cmd_len, s->data_len);
392
 
            s->residue = 0;
393
 
            s->scsi_dev->send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
394
 
            /* ??? Should check that USB and SCSI data transfer
395
 
               directions match.  */
396
 
            if (s->residue == 0) {
397
 
                if (s->mode == USB_MSDM_DATAIN) {
398
 
                    s->scsi_dev->read_data(s->scsi_dev, s->tag);
399
 
                } else if (s->mode == USB_MSDM_DATAOUT) {
400
 
                    s->scsi_dev->write_data(s->scsi_dev, s->tag);
401
 
                }
402
 
            }
403
 
            ret = len;
404
 
            break;
405
 
 
406
 
        case USB_MSDM_DATAOUT:
407
 
            DPRINTF("Data out %d/%d\n", len, s->data_len);
408
 
            if (len > s->data_len)
409
 
                goto fail;
410
 
 
411
 
            s->usb_buf = data;
412
 
            s->usb_len = len;
413
 
            if (s->scsi_len) {
414
 
                usb_msd_copy_data(s);
415
 
            }
416
 
            if (s->residue && s->usb_len) {
417
 
                s->data_len -= s->usb_len;
418
 
                if (s->data_len == 0)
419
 
                    s->mode = USB_MSDM_CSW;
420
 
                s->usb_len = 0;
421
 
            }
422
 
            if (s->usb_len) {
423
 
                DPRINTF("Deferring packet %p\n", p);
424
 
                usb_defer_packet(p, usb_msd_cancel_io, s);
425
 
                s->packet = p;
426
 
                ret = USB_RET_ASYNC;
427
 
            } else {
428
 
                ret = len;
429
 
            }
430
 
            break;
431
 
 
432
 
        default:
433
 
            DPRINTF("Unexpected write (len %d)\n", len);
434
 
            goto fail;
435
 
        }
436
 
        break;
437
 
 
438
 
    case USB_TOKEN_IN:
439
 
        if (devep != 1)
440
 
            goto fail;
441
 
 
442
 
        switch (s->mode) {
443
 
        case USB_MSDM_DATAOUT:
444
 
            if (s->data_len != 0 || len < 13)
445
 
                goto fail;
446
 
            /* Waiting for SCSI write to complete.  */
447
 
            usb_defer_packet(p, usb_msd_cancel_io, s);
448
 
            s->packet = p;
449
 
            ret = USB_RET_ASYNC;
450
 
            break;
451
 
 
452
 
        case USB_MSDM_CSW:
453
 
            DPRINTF("Command status %d tag 0x%x, len %d\n",
454
 
                    s->result, s->tag, len);
455
 
            if (len < 13)
456
 
                goto fail;
457
 
 
458
 
            s->usb_len = len;
459
 
            s->usb_buf = data;
460
 
            usb_msd_send_status(s);
461
 
            s->mode = USB_MSDM_CBW;
462
 
            ret = 13;
463
 
            break;
464
 
 
465
 
        case USB_MSDM_DATAIN:
466
 
            DPRINTF("Data in %d/%d\n", len, s->data_len);
467
 
            if (len > s->data_len)
468
 
                len = s->data_len;
469
 
            s->usb_buf = data;
470
 
            s->usb_len = len;
471
 
            if (s->scsi_len) {
472
 
                usb_msd_copy_data(s);
473
 
            }
474
 
            if (s->residue && s->usb_len) {
475
 
                s->data_len -= s->usb_len;
476
 
                memset(s->usb_buf, 0, s->usb_len);
477
 
                if (s->data_len == 0)
478
 
                    s->mode = USB_MSDM_CSW;
479
 
                s->usb_len = 0;
480
 
            }
481
 
            if (s->usb_len) {
482
 
                DPRINTF("Deferring packet %p\n", p);
483
 
                usb_defer_packet(p, usb_msd_cancel_io, s);
484
 
                s->packet = p;
485
 
                ret = USB_RET_ASYNC;
486
 
            } else {
487
 
                ret = len;
488
 
            }
489
 
            break;
490
 
 
491
 
        default:
492
 
            DPRINTF("Unexpected read (len %d)\n", len);
493
 
            goto fail;
494
 
        }
495
 
        break;
496
 
 
497
 
    default:
498
 
        DPRINTF("Bad token\n");
499
 
    fail:
500
 
        ret = USB_RET_STALL;
501
 
        break;
502
 
    }
503
 
 
504
 
    return ret;
505
 
}
506
 
 
507
 
static void usb_msd_handle_destroy(USBDevice *dev)
508
 
{
509
 
    MSDState *s = (MSDState *)dev;
510
 
 
511
 
    s->scsi_dev->destroy(s->scsi_dev);
512
 
    bdrv_delete(s->bs);
513
 
    qemu_free(s);
514
 
}
515
 
 
516
 
USBDevice *usb_msd_init(const char *filename)
517
 
{
518
 
    MSDState *s;
519
 
    BlockDriverState *bdrv;
520
 
    BlockDriver *drv = NULL;
521
 
    const char *p1;
522
 
    char fmt[32];
523
 
 
524
 
    p1 = strchr(filename, ':');
525
 
    if (p1++) {
526
 
        const char *p2;
527
 
 
528
 
        if (strstart(filename, "format=", &p2)) {
529
 
            int len = MIN(p1 - p2, sizeof(fmt));
530
 
            pstrcpy(fmt, len, p2);
531
 
 
532
 
            drv = bdrv_find_format(fmt);
533
 
            if (!drv) {
534
 
                printf("invalid format %s\n", fmt);
535
 
                return NULL;
536
 
            }
537
 
        } else if (*filename != ':') {
538
 
            printf("unrecognized USB mass-storage option %s\n", filename);
539
 
            return NULL;
540
 
        }
541
 
 
542
 
        filename = p1;
543
 
    }
544
 
 
545
 
    if (!*filename) {
546
 
        printf("block device specification needed\n");
547
 
        return NULL;
548
 
    }
549
 
 
550
 
    s = qemu_mallocz(sizeof(MSDState));
551
 
    if (!s)
552
 
        return NULL;
553
 
 
554
 
    bdrv = bdrv_new("usb");
555
 
    if (bdrv_open2(bdrv, filename, 0, drv) < 0)
556
 
        goto fail;
557
 
    if (qemu_key_check(bdrv, filename))
558
 
        goto fail;
559
 
    s->bs = bdrv;
560
 
 
561
 
    s->dev.speed = USB_SPEED_FULL;
562
 
    s->dev.handle_packet = usb_generic_handle_packet;
563
 
 
564
 
    s->dev.handle_reset = usb_msd_handle_reset;
565
 
    s->dev.handle_control = usb_msd_handle_control;
566
 
    s->dev.handle_data = usb_msd_handle_data;
567
 
    s->dev.handle_destroy = usb_msd_handle_destroy;
568
 
 
569
 
    snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
570
 
             filename);
571
 
 
572
 
    s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s);
573
 
    usb_msd_handle_reset((USBDevice *)s);
574
 
    return (USBDevice *)s;
575
 
 fail:
576
 
    qemu_free(s);
577
 
    return NULL;
578
 
}