symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/usb-msd.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 }