Statistics
| Branch: | Revision:

root / hw / usb-msd.c @ 4d611c9a

History | View | Annotate | Download (11.8 kB)

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 "vl.h"
11

    
12
//#define DEBUG_MSD
13

    
14
#ifdef DEBUG_MSD
15
#define DPRINTF(fmt, args...) \
16
do { printf("usb-msd: " fmt , ##args); } while (0)
17
#else
18
#define DPRINTF(fmt, args...) do {} while(0)
19
#endif
20

    
21
/* USB requests.  */
22
#define MassStorageReset  0xff
23
#define GetMaxLun         0xfe
24

    
25
enum USBMSDMode {
26
    USB_MSDM_CBW, /* Command Block.  */
27
    USB_MSDM_DATAOUT, /* Tranfer data to device.  */
28
    USB_MSDM_DATAIN, /* Transfer data from device.  */
29
    USB_MSDM_CSW /* Command Status.  */
30
};
31

    
32
typedef struct {
33
    USBDevice dev;
34
    enum USBMSDMode mode;
35
    uint32_t data_len;
36
    uint32_t transfer_len;
37
    uint32_t tag;
38
    SCSIDevice *scsi_dev;
39
    int result;
40
    /* For async completion.  */
41
    USBPacket *packet;
42
} MSDState;
43

    
44
static const uint8_t qemu_msd_dev_descriptor[] = {
45
        0x12,       /*  u8 bLength; */
46
        0x01,       /*  u8 bDescriptorType; Device */
47
        0x10, 0x00, /*  u16 bcdUSB; v1.0 */
48

    
49
        0x00,            /*  u8  bDeviceClass; */
50
        0x00,            /*  u8  bDeviceSubClass; */
51
        0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
52
        0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
53

    
54
        /* Vendor and product id are arbitrary.  */
55
        0x00, 0x00, /*  u16 idVendor; */
56
         0x00, 0x00, /*  u16 idProduct; */
57
        0x00, 0x00, /*  u16 bcdDevice */
58

    
59
        0x01,       /*  u8  iManufacturer; */
60
        0x02,       /*  u8  iProduct; */
61
        0x03,       /*  u8  iSerialNumber; */
62
        0x01        /*  u8  bNumConfigurations; */
63
};
64

    
65
static const uint8_t qemu_msd_config_descriptor[] = {
66

    
67
        /* one configuration */
68
        0x09,       /*  u8  bLength; */
69
        0x02,       /*  u8  bDescriptorType; Configuration */
70
        0x20, 0x00, /*  u16 wTotalLength; */
71
        0x01,       /*  u8  bNumInterfaces; (1) */
72
        0x01,       /*  u8  bConfigurationValue; */
73
        0x00,       /*  u8  iConfiguration; */
74
        0xc0,       /*  u8  bmAttributes; 
75
                                 Bit 7: must be set,
76
                                     6: Self-powered,
77
                                     5: Remote wakeup,
78
                                     4..0: resvd */
79
        0x00,       /*  u8  MaxPower; */
80
      
81
        /* one interface */
82
        0x09,       /*  u8  if_bLength; */
83
        0x04,       /*  u8  if_bDescriptorType; Interface */
84
        0x00,       /*  u8  if_bInterfaceNumber; */
85
        0x00,       /*  u8  if_bAlternateSetting; */
86
        0x02,       /*  u8  if_bNumEndpoints; */
87
        0x08,       /*  u8  if_bInterfaceClass; MASS STORAGE */
88
        0x06,       /*  u8  if_bInterfaceSubClass; SCSI */
89
        0x50,       /*  u8  if_bInterfaceProtocol; Bulk Only */
90
        0x00,       /*  u8  if_iInterface; */
91
     
92
        /* Bulk-In endpoint */
93
        0x07,       /*  u8  ep_bLength; */
94
        0x05,       /*  u8  ep_bDescriptorType; Endpoint */
95
        0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
96
         0x02,       /*  u8  ep_bmAttributes; Bulk */
97
         0x40, 0x00, /*  u16 ep_wMaxPacketSize; */
98
        0x00,       /*  u8  ep_bInterval; */
99

    
100
        /* Bulk-Out endpoint */
101
        0x07,       /*  u8  ep_bLength; */
102
        0x05,       /*  u8  ep_bDescriptorType; Endpoint */
103
        0x02,       /*  u8  ep_bEndpointAddress; OUT Endpoint 2 */
104
         0x02,       /*  u8  ep_bmAttributes; Bulk */
105
         0x40, 0x00, /*  u16 ep_wMaxPacketSize; */
106
        0x00        /*  u8  ep_bInterval; */
107
};
108

    
109
static void usb_msd_command_complete(void *opaque, uint32_t reason, int fail)
110
{
111
    MSDState *s = (MSDState *)opaque;
112
    USBPacket *p;
113

    
114
    s->data_len -= s->transfer_len;
115
    s->transfer_len = 0;
116
    if (reason == SCSI_REASON_DONE) {
117
        DPRINTF("Command complete %d\n", fail);
118
        s->result = fail;
119
        s->mode = USB_MSDM_CSW;
120
    }
121
    if (s->packet) {
122
        /* Set s->packet to NULL before calling usb_packet_complete because
123
           annother request may be issues before usb_packet_complete returns.
124
         */
125
        DPRINTF("Packet complete %p\n", p);
126
        p = s->packet;
127
        s->packet = NULL;
128
        usb_packet_complete(p);
129
    }
130
}
131

    
132
static void usb_msd_handle_reset(USBDevice *dev)
133
{
134
    MSDState *s = (MSDState *)dev;
135

    
136
    DPRINTF("Reset\n");
137
    s->mode = USB_MSDM_CBW;
138
}
139

    
140
static int usb_msd_handle_control(USBDevice *dev, int request, int value,
141
                                  int index, int length, uint8_t *data)
142
{
143
    MSDState *s = (MSDState *)dev;
144
    int ret = 0;
145

    
146
    switch (request) {
147
    case DeviceRequest | USB_REQ_GET_STATUS:
148
        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
149
            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
150
        data[1] = 0x00;
151
        ret = 2;
152
        break;
153
    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
154
        if (value == USB_DEVICE_REMOTE_WAKEUP) {
155
            dev->remote_wakeup = 0;
156
        } else {
157
            goto fail;
158
        }
159
        ret = 0;
160
        break;
161
    case DeviceOutRequest | USB_REQ_SET_FEATURE:
162
        if (value == USB_DEVICE_REMOTE_WAKEUP) {
163
            dev->remote_wakeup = 1;
164
        } else {
165
            goto fail;
166
        }
167
        ret = 0;
168
        break;
169
    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
170
        dev->addr = value;
171
        ret = 0;
172
        break;
173
    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
174
        switch(value >> 8) {
175
        case USB_DT_DEVICE:
176
            memcpy(data, qemu_msd_dev_descriptor, 
177
                   sizeof(qemu_msd_dev_descriptor));
178
            ret = sizeof(qemu_msd_dev_descriptor);
179
            break;
180
        case USB_DT_CONFIG:
181
            memcpy(data, qemu_msd_config_descriptor, 
182
                   sizeof(qemu_msd_config_descriptor));
183
            ret = sizeof(qemu_msd_config_descriptor);
184
            break;
185
        case USB_DT_STRING:
186
            switch(value & 0xff) {
187
            case 0:
188
                /* language ids */
189
                data[0] = 4;
190
                data[1] = 3;
191
                data[2] = 0x09;
192
                data[3] = 0x04;
193
                ret = 4;
194
                break;
195
            case 1:
196
                /* vendor description */
197
                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
198
                break;
199
            case 2:
200
                /* product description */
201
                ret = set_usb_string(data, "QEMU USB HARDDRIVE");
202
                break;
203
            case 3:
204
                /* serial number */
205
                ret = set_usb_string(data, "1");
206
                break;
207
            default:
208
                goto fail;
209
            }
210
            break;
211
        default:
212
            goto fail;
213
        }
214
        break;
215
    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
216
        data[0] = 1;
217
        ret = 1;
218
        break;
219
    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
220
        ret = 0;
221
        break;
222
    case DeviceRequest | USB_REQ_GET_INTERFACE:
223
        data[0] = 0;
224
        ret = 1;
225
        break;
226
    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
227
        ret = 0;
228
        break;
229
    case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
230
        if (value == 0 && index != 0x81) { /* clear ep halt */
231
            goto fail;
232
        }
233
        ret = 0;
234
        break;
235
        /* Class specific requests.  */
236
    case MassStorageReset:
237
        /* Reset state ready for the next CBW.  */
238
        s->mode = USB_MSDM_CBW;
239
        ret = 0;
240
        break;
241
    case GetMaxLun:
242
        data[0] = 0;
243
        ret = 1;
244
        break;
245
    default:
246
    fail:
247
        ret = USB_RET_STALL;
248
        break;
249
    }
250
    return ret;
251
}
252

    
253
struct usb_msd_cbw {
254
    uint32_t sig;
255
    uint32_t tag;
256
    uint32_t data_len;
257
    uint8_t flags;
258
    uint8_t lun;
259
    uint8_t cmd_len;
260
    uint8_t cmd[16];
261
};
262

    
263
struct usb_msd_csw {
264
    uint32_t sig;
265
    uint32_t tag;
266
    uint32_t residue;
267
    uint8_t status;
268
};
269

    
270
static void usb_msd_cancel_io(USBPacket *p, void *opaque)
271
{
272
    MSDState *s = opaque;
273
    scsi_cancel_io(s->scsi_dev);
274
    s->packet = NULL;
275
}
276

    
277
static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
278
{
279
    MSDState *s = (MSDState *)dev;
280
    int ret = 0;
281
    struct usb_msd_cbw cbw;
282
    struct usb_msd_csw csw;
283
    uint8_t devep = p->devep;
284
    uint8_t *data = p->data;
285
    int len = p->len;
286

    
287
    switch (p->pid) {
288
    case USB_TOKEN_OUT:
289
        if (devep != 2)
290
            goto fail;
291

    
292
        switch (s->mode) {
293
        case USB_MSDM_CBW:
294
            if (len != 31) {
295
                fprintf(stderr, "usb-msd: Bad CBW size");
296
                goto fail;
297
            }
298
            memcpy(&cbw, data, 31);
299
            if (le32_to_cpu(cbw.sig) != 0x43425355) {
300
                fprintf(stderr, "usb-msd: Bad signature %08x\n",
301
                        le32_to_cpu(cbw.sig));
302
                goto fail;
303
            }
304
            DPRINTF("Command on LUN %d\n", cbw.lun);
305
            if (cbw.lun != 0) {
306
                fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
307
                goto fail;
308
            }
309
            s->tag = le32_to_cpu(cbw.tag);
310
            s->data_len = le32_to_cpu(cbw.data_len);
311
            if (s->data_len == 0) {
312
                s->mode = USB_MSDM_CSW;
313
            } else if (cbw.flags & 0x80) {
314
                s->mode = USB_MSDM_DATAIN;
315
            } else {
316
                s->mode = USB_MSDM_DATAOUT;
317
            }
318
            DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
319
                    s->tag, cbw.flags, cbw.cmd_len, s->data_len);
320
            scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
321
            ret = len;
322
            break;
323

    
324
        case USB_MSDM_DATAOUT:
325
            DPRINTF("Data out %d/%d\n", len, s->data_len);
326
            if (len > s->data_len)
327
                goto fail;
328

    
329
            s->transfer_len = len;
330
            if (scsi_write_data(s->scsi_dev, data, len))
331
                goto fail;
332

    
333
            if (s->transfer_len == 0) {
334
                ret = len;
335
            } else {
336
                DPRINTF("Deferring packet %p\n", p);
337
                usb_defer_packet(p, usb_msd_cancel_io, s);
338
                s->packet = p;
339
                ret = USB_RET_ASYNC;
340
            }
341
            break;
342

    
343
        default:
344
            DPRINTF("Unexpected write (len %d)\n", len);
345
            goto fail;
346
        }
347
        break;
348

    
349
    case USB_TOKEN_IN:
350
        if (devep != 1)
351
            goto fail;
352

    
353
        switch (s->mode) {
354
        case USB_MSDM_CSW:
355
            DPRINTF("Command status %d tag 0x%x, len %d\n",
356
                    s->result, s->tag, len);
357
            if (len < 13)
358
                goto fail;
359

    
360
            csw.sig = cpu_to_le32(0x53425355);
361
            csw.tag = cpu_to_le32(s->tag);
362
            csw.residue = 0;
363
            csw.status = s->result;
364
            memcpy(data, &csw, 13);
365
            ret = 13;
366
            s->mode = USB_MSDM_CBW;
367
            break;
368

    
369
        case USB_MSDM_DATAIN:
370
            DPRINTF("Data in %d/%d\n", len, s->data_len);
371
            if (len > s->data_len)
372
                len = s->data_len;
373

    
374
            s->transfer_len = len;
375
            if (scsi_read_data(s->scsi_dev, data, len))
376
                goto fail;
377

    
378
            if (s->transfer_len == 0) {
379
                ret = len;
380
            } else {
381
                DPRINTF("Deferring packet %p\n", p);
382
                usb_defer_packet(p, usb_msd_cancel_io, s);
383
                s->packet = p;
384
                ret = USB_RET_ASYNC;
385
            }
386
            break;
387

    
388
        default:
389
            DPRINTF("Unexpected read (len %d)\n", len);
390
            goto fail;
391
        }
392
        break;
393

    
394
    default:
395
        DPRINTF("Bad token\n");
396
    fail:
397
        ret = USB_RET_STALL;
398
        break;
399
    }
400

    
401
    return ret;
402
}
403

    
404
static void usb_msd_handle_destroy(USBDevice *dev)
405
{
406
    MSDState *s = (MSDState *)dev;
407

    
408
    scsi_disk_destroy(s->scsi_dev);
409
    qemu_free(s);
410
}
411

    
412
USBDevice *usb_msd_init(const char *filename)
413
{
414
    MSDState *s;
415
    BlockDriverState *bdrv;
416

    
417
    s = qemu_mallocz(sizeof(MSDState));
418
    if (!s)
419
        return NULL;
420

    
421
    bdrv = bdrv_new("usb");
422
    bdrv_open(bdrv, filename, 0);
423

    
424
    s->dev.speed = USB_SPEED_FULL;
425
    s->dev.handle_packet = usb_generic_handle_packet;
426

    
427
    s->dev.handle_reset = usb_msd_handle_reset;
428
    s->dev.handle_control = usb_msd_handle_control;
429
    s->dev.handle_data = usb_msd_handle_data;
430
    s->dev.handle_destroy = usb_msd_handle_destroy;
431

    
432
    snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
433
             filename);
434

    
435
    s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s);
436
    usb_msd_handle_reset((USBDevice *)s);
437
    return (USBDevice *)s;
438
}