freemyipod r893 - Code Review

Jump to: navigation, search
Repository:freemyipod
Revision:r892‎ | r893 | r894 >
Date:15:29, 5 August 2013
Author:theseven
Status:new
Tags:
Comment:
New app: Userspace USB mass storage test
Modified paths:
  • /apps/umstest (added) (history)
  • /apps/umstest/Makefile (added) (history)
  • /apps/umstest/SOURCES (added) (history)
  • /apps/umstest/ls.x (added) (history)
  • /apps/umstest/main.c (added) (history)
  • /apps/umstest/version.h (added) (history)

Diff [purge]

Index: apps/umstest/main.c
@@ -0,0 +1,870 @@
 2+//
 3+//
 4+// Copyright 2013 TheSeven
 5+//
 6+//
 7+// This file is part of emCORE.
 8+//
 9+// emCORE is free software: you can redistribute it and/or
 10+// modify it under the terms of the GNU General Public License as
 11+// published by the Free Software Foundation, either version 2 of the
 12+// License, or (at your option) any later version.
 13+//
 14+// emCORE is distributed in the hope that it will be useful,
 15+// but WITHOUT ANY WARRANTY; without even the implied warranty of
 16+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 17+// See the GNU General Public License for more details.
 18+//
 19+// You should have received a copy of the GNU General Public License along
 20+// with emCORE. If not, see <http://www.gnu.org/licenses/>.
 21+//
 22+//
 23+
 24+
 25+#define LITTLE_ENDIAN
 26+
 27+
 28+#include "emcoreapp.h"
 29+
 30+
 31+#define SCSI_TEST_UNIT_READY 0x00
 32+#define SCSI_INQUIRY 0x12
 33+#define SCSI_MODE_SENSE_6 0x1a
 34+#define SCSI_MODE_SENSE_10 0x5a
 35+#define SCSI_REQUEST_SENSE 0x03
 36+#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e
 37+#define SCSI_READ_CAPACITY 0x25
 38+#define SCSI_READ_FORMAT_CAPACITY 0x23
 39+#define SCSI_READ_10 0x28
 40+#define SCSI_WRITE_10 0x2a
 41+#define SCSI_START_STOP_UNIT 0x1b
 42+#define SCSI_REPORT_LUNS 0xa0
 43+#define SCSI_WRITE_BUFFER 0x3b
 44+
 45+#define SENSE_NOT_READY 0x02
 46+#define SENSE_MEDIUM_ERROR 0x03
 47+#define SENSE_ILLEGAL_REQUEST 0x05
 48+#define SENSE_UNIT_ATTENTION 0x06
 49+
 50+#define ASC_MEDIUM_NOT_PRESENT 0x3a
 51+#define ASC_INVALID_FIELD_IN_CBD 0x24
 52+#define ASC_LBA_OUT_OF_RANGE 0x21
 53+#define ASC_WRITE_ERROR 0x0C
 54+#define ASC_READ_ERROR 0x11
 55+#define ASC_NOT_READY 0x04
 56+#define ASC_INVALID_COMMAND 0x20
 57+
 58+#define ASCQ_BECOMING_READY 0x01
 59+
 60+#define DIRECT_ACCESS_DEVICE 0x00
 61+#define DEVICE_REMOVABLE 0x80
 62+
 63+#define SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA 0x02000000
 64+
 65+
 66+#define RAMDISK_SECTORSIZE 512
 67+#define RAMDISK_SECTORS 2048
 68+
 69+
 70+static const struct usb_devicedescriptor usb_devicedescriptor =
 71+{
 72+ .bLength = sizeof(struct usb_devicedescriptor),
 73+ .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE,
 74+ .bcdUSB = 0x0200,
 75+ .bDeviceClass = 0,
 76+ .bDeviceSubClass = 0,
 77+ .bDeviceProtocol = 0,
 78+ .bMaxPacketSize0 = 64,
 79+ .idVendor = 0xffff,
 80+ .idProduct = 0xe000,
 81+ .bcdDevice = 2,
 82+ .iManufacturer = 1,
 83+ .iProduct = 2,
 84+ .iSerialNumber = 0,
 85+ .bNumConfigurations = 1,
 86+};
 87+
 88+static struct __attribute__((packed)) _usb_config1_descriptors
 89+{
 90+ struct usb_configurationdescriptor c1;
 91+ struct usb_interfacedescriptor c1_i0_a0;
 92+ struct usb_endpointdescriptor c1_i0_a0_e1out;
 93+ struct usb_endpointdescriptor c1_i0_a0_e1in;
 94+} usb_config1_descriptors =
 95+{
 96+ .c1 =
 97+ {
 98+ .bLength = sizeof(struct usb_configurationdescriptor),
 99+ .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION,
 100+ .wTotalLength = sizeof(struct _usb_config1_descriptors),
 101+ .bNumInterfaces = 1,
 102+ .bConfigurationValue = 1,
 103+ .iConfiguration = 0,
 104+ .bmAttributes = { .buspowered = 1, .selfpowered = 1 },
 105+ .bMaxPower = 100 / 2,
 106+ },
 107+ .c1_i0_a0 =
 108+ {
 109+ .bLength = sizeof(struct usb_interfacedescriptor),
 110+ .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
 111+ .bInterfaceNumber = 0,
 112+ .bAlternateSetting = 0,
 113+ .bNumEndpoints = 2,
 114+ .bInterfaceClass = 0x08,
 115+ .bInterfaceSubClass = 0x06,
 116+ .bInterfaceProtocol = 0x50,
 117+ .iInterface = 0,
 118+ },
 119+ .c1_i0_a0_e1out =
 120+ {
 121+ .bLength = sizeof(struct usb_endpointdescriptor),
 122+ .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
 123+ .bEndpointAddress = { .number = 0, .direction = USB_ENDPOINT_DIRECTION_OUT },
 124+ .bmAttributes = { .type = USB_ENDPOINT_ATTRIBUTE_TYPE_BULK },
 125+ .wMaxPacketSize = 512,
 126+ .bInterval = 1,
 127+ },
 128+ .c1_i0_a0_e1in =
 129+ {
 130+ .bLength = sizeof(struct usb_endpointdescriptor),
 131+ .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
 132+ .bEndpointAddress = { .number = 0, .direction = USB_ENDPOINT_DIRECTION_IN },
 133+ .bmAttributes = { .type = USB_ENDPOINT_ATTRIBUTE_TYPE_BULK },
 134+ .wMaxPacketSize = 512,
 135+ .bInterval = 1,
 136+ },
 137+};
 138+
 139+static const struct usb_stringdescriptor usb_string_language =
 140+{
 141+ .bLength = sizeof(usb_string_language) + sizeof(*usb_string_language.wString),
 142+ .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
 143+ .wString = { 0x0409 },
 144+};
 145+
 146+static const struct usb_stringdescriptor usb_string_vendor =
 147+{
 148+ .bLength = sizeof(usb_string_vendor) + sizeof(*usb_string_vendor.wString) * 14,
 149+ .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
 150+ .wString = { 'f', 'r', 'e', 'e', 'm', 'y', 'i', 'p', 'o', 'd', '.', 'o', 'r', 'g' },
 151+};
 152+
 153+static const struct usb_stringdescriptor usb_string_product =
 154+{
 155+ .bLength = sizeof(usb_string_product) + sizeof(*usb_string_product.wString) * 28,
 156+ .bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
 157+ .wString = { 'e', 'm', 'C', 'O', 'R', 'E', ' ', 'U', 'S', 'B', ' ', 'm', 'a', 's', 's', ' ', 's', 't', 'o', 'r', 'a', 'g', 'e', ' ', 't', 'e', 's', 't' },
 158+};
 159+
 160+static const struct usb_stringdescriptor* usb_stringdescriptors[] =
 161+{
 162+ &usb_string_language,
 163+ &usb_string_vendor,
 164+ &usb_string_product,
 165+};
 166+
 167+struct __attribute__((packed,aligned(32))) command_block_wrapper
 168+{
 169+ unsigned int signature;
 170+ unsigned int tag;
 171+ unsigned int data_transfer_length;
 172+ unsigned char flags;
 173+ unsigned char lun;
 174+ unsigned char command_length;
 175+ unsigned char command_block[16];
 176+};
 177+
 178+struct __attribute__((packed)) command_status_wrapper
 179+{
 180+ unsigned int signature;
 181+ unsigned int tag;
 182+ unsigned int data_residue;
 183+ unsigned char status;
 184+};
 185+
 186+struct __attribute__((packed)) inquiry_data
 187+{
 188+ unsigned char DeviceType;
 189+ unsigned char DeviceTypeModifier;
 190+ unsigned char Versions;
 191+ unsigned char Format;
 192+ unsigned char AdditionalLength;
 193+ unsigned char Reserved[2];
 194+ unsigned char Capability;
 195+ char VendorId[8];
 196+ char ProductId[16];
 197+ char ProductRevisionLevel[4];
 198+};
 199+
 200+struct __attribute__((packed)) report_lun_data
 201+{
 202+ unsigned int lun_list_length;
 203+ unsigned int reserved1;
 204+ unsigned char luns[1][8];
 205+};
 206+
 207+struct __attribute__((packed)) sense_data
 208+{
 209+ unsigned char ResponseCode;
 210+ unsigned char Obsolete;
 211+ unsigned char fei_sensekey;
 212+ unsigned int Information;
 213+ unsigned char AdditionalSenseLength;
 214+ unsigned int CommandSpecificInformation;
 215+ unsigned char AdditionalSenseCode;
 216+ unsigned char AdditionalSenseCodeQualifier;
 217+ unsigned char FieldReplaceableUnitCode;
 218+ unsigned char SKSV;
 219+ unsigned short SenseKeySpecific;
 220+};
 221+
 222+struct __attribute__((packed)) mode_sense_bdesc_longlba
 223+{
 224+ unsigned char num_blocks[8];
 225+ unsigned char reserved[4];
 226+ unsigned char block_size[4];
 227+};
 228+
 229+struct __attribute__((packed)) mode_sense_bdesc_shortlba
 230+{
 231+ unsigned char density_code;
 232+ unsigned char num_blocks[3];
 233+ unsigned char reserved;
 234+ unsigned char block_size[3];
 235+};
 236+
 237+struct __attribute__((packed)) mode_sense_data_10
 238+{
 239+ unsigned short mode_data_length;
 240+ unsigned char medium_type;
 241+ unsigned char device_specific;
 242+ unsigned char longlba;
 243+ unsigned char reserved;
 244+ unsigned short block_descriptor_length;
 245+ struct mode_sense_bdesc_longlba block_descriptor;
 246+};
 247+
 248+struct __attribute__((packed)) mode_sense_data_6
 249+{
 250+ unsigned char mode_data_length;
 251+ unsigned char medium_type;
 252+ unsigned char device_specific;
 253+ unsigned char block_descriptor_length;
 254+ struct mode_sense_bdesc_shortlba block_descriptor;
 255+};
 256+
 257+struct __attribute__((packed)) capacity
 258+{
 259+ unsigned int block_count;
 260+ unsigned int block_size;
 261+};
 262+
 263+struct __attribute__((packed)) format_capacity
 264+{
 265+ unsigned int following_length;
 266+ unsigned int block_count;
 267+ unsigned int block_size;
 268+};
 269+
 270+union __attribute__((aligned(32)))
 271+{
 272+ struct inquiry_data inquiry;
 273+ struct capacity capacity_data;
 274+ struct format_capacity format_capacity_data;
 275+ struct sense_data sense_data;
 276+ struct mode_sense_data_6 ms_data_6;
 277+ struct mode_sense_data_10 ms_data_10;
 278+ struct report_lun_data lun_data;
 279+ struct command_status_wrapper csw;
 280+} tb;
 281+
 282+static enum
 283+{
 284+ WAITING_FOR_COMMAND,
 285+ SENDING_BLOCKS,
 286+ SENDING_RESULT,
 287+ SENDING_FAILED_RESULT,
 288+ RECEIVING_BLOCKS,
 289+ WAITING_FOR_CSW_COMPLETION
 290+} state = WAITING_FOR_COMMAND;
 291+
 292+static struct
 293+{
 294+ unsigned int sector;
 295+ unsigned int count;
 296+ unsigned int orig_count;
 297+ unsigned int cur_cmd;
 298+ unsigned int tag;
 299+ unsigned int lun;
 300+ unsigned int last_result;
 301+} cur_cmd;
 302+
 303+static struct
 304+{
 305+ unsigned char sense_key;
 306+ unsigned char information;
 307+ unsigned char asc;
 308+ unsigned char ascq;
 309+} cur_sense_data;
 310+
 311+static union usb_endpoint_number outep = { .number = 0, .direction = USB_ENDPOINT_DIRECTION_OUT };
 312+static union usb_endpoint_number inep = { .number = 0, .direction = USB_ENDPOINT_DIRECTION_IN };
 313+
 314+static struct command_block_wrapper cbw;
 315+static int maxpacket = 512;
 316+static int maxlen;
 317+static int length;
 318+static bool locked;
 319+static const struct usb_instance* usb;
 320+static volatile bool ejected = false;
 321+static uint8_t __attribute__((aligned(32))) ramdisk[RAMDISK_SECTORS][RAMDISK_SECTORSIZE];
 322+
 323+static void listen()
 324+{
 325+ usb_start_rx(usb, outep, &cbw, sizeof(cbw));
 326+}
 327+
 328+static void send_csw(int status)
 329+{
 330+ tb.csw.signature = 0x53425355;
 331+ tb.csw.tag = cur_cmd.tag;
 332+ tb.csw.data_residue = 0;
 333+ tb.csw.status = status;
 334+
 335+ state = WAITING_FOR_CSW_COMPLETION;
 336+ usb_start_tx(usb, inep, &tb.csw, sizeof(tb.csw));
 337+
 338+ if (!status)
 339+ {
 340+ cur_sense_data.sense_key = 0;
 341+ cur_sense_data.information = 0;
 342+ cur_sense_data.asc = 0;
 343+ cur_sense_data.ascq = 0;
 344+ }
 345+}
 346+
 347+static void receive_block_data(void* data, int size)
 348+{
 349+ length = size;
 350+ usb_start_rx(usb, outep, data, size);
 351+ state = RECEIVING_BLOCKS;
 352+}
 353+
 354+static void send_block_data(void* data, int size)
 355+{
 356+ length = size;
 357+ usb_start_tx(usb, inep, data, size);
 358+ state = SENDING_BLOCKS;
 359+}
 360+
 361+static void send_command_result(void* data, int size)
 362+{
 363+ length = size;
 364+ usb_start_tx(usb, inep, data, size);
 365+ state = SENDING_RESULT;
 366+}
 367+
 368+static void send_command_failed_result()
 369+{
 370+ usb_start_tx(usb, inep, NULL, 0);
 371+ state = SENDING_FAILED_RESULT;
 372+}
 373+
 374+static void send_and_read_next()
 375+{
 376+ if (cur_cmd.last_result)
 377+ {
 378+ send_csw(1);
 379+ cur_sense_data.sense_key = SENSE_MEDIUM_ERROR;
 380+ cur_sense_data.asc = ASC_READ_ERROR;
 381+ cur_sense_data.ascq = 0;
 382+ return;
 383+ }
 384+ send_block_data(ramdisk[cur_cmd.sector], MIN(maxlen, cur_cmd.count * RAMDISK_SECTORSIZE));
 385+
 386+ cur_cmd.sector += maxlen / RAMDISK_SECTORSIZE;
 387+ cur_cmd.count -= MIN(cur_cmd.count, maxlen / RAMDISK_SECTORSIZE);
 388+}
 389+
 390+static void copy_padded(char* dest, char* src, int len)
 391+{
 392+ int i = 0;
 393+ while (src[i] && i < len)
 394+ {
 395+ dest[i] = src[i];
 396+ i++;
 397+ }
 398+ while(i < len) dest[i++] = ' ';
 399+}
 400+
 401+static void fill_inquiry()
 402+{
 403+ memset(&tb.inquiry, 0, sizeof(tb.inquiry));
 404+ copy_padded(tb.inquiry.VendorId, "emCORE", sizeof(tb.inquiry.VendorId));
 405+ copy_padded(tb.inquiry.ProductId, "UMS Test", sizeof(tb.inquiry.ProductId));
 406+ copy_padded(tb.inquiry.ProductRevisionLevel, "0.1", sizeof(tb.inquiry.ProductRevisionLevel));
 407+
 408+ tb.inquiry.DeviceType = DIRECT_ACCESS_DEVICE;
 409+ tb.inquiry.AdditionalLength = 0x1f;
 410+ tb.inquiry.Versions = 4; // SPC-2
 411+ tb.inquiry.Format = 2; // SPC-2/3 inquiry format
 412+ tb.inquiry.DeviceTypeModifier = DEVICE_REMOVABLE;
 413+}
 414+
 415+static void handle_scsi(struct command_block_wrapper* cbw)
 416+{
 417+ unsigned int length = cbw->data_transfer_length;
 418+
 419+ if (cbw->signature != 0x43425355)
 420+ {
 421+ usb_set_stall(usb, outep, true);
 422+ usb_set_stall(usb, inep, true);
 423+ return;
 424+ }
 425+ cur_cmd.tag = cbw->tag;
 426+ cur_cmd.lun = cbw->lun;
 427+ cur_cmd.cur_cmd = cbw->command_block[0];
 428+
 429+ switch (cbw->command_block[0])
 430+ {
 431+ case SCSI_TEST_UNIT_READY:
 432+ if (!ejected) send_csw(0);
 433+ else
 434+ {
 435+ send_csw(1);
 436+ cur_sense_data.sense_key = SENSE_NOT_READY;
 437+ cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 438+ cur_sense_data.ascq = 0;
 439+ }
 440+ break;
 441+
 442+ case SCSI_REPORT_LUNS:
 443+ {
 444+ memset(&tb.lun_data, 0, sizeof(struct report_lun_data));
 445+ tb.lun_data.lun_list_length = 0x08000000;
 446+ send_command_result(&tb.lun_data, MIN(16, length));
 447+ break;
 448+ }
 449+
 450+ case SCSI_INQUIRY:
 451+ fill_inquiry();
 452+ length = MIN(length, cbw->command_block[4]);
 453+ send_command_result(&tb.inquiry, MIN(sizeof(tb.inquiry), length));
 454+ break;
 455+
 456+ case SCSI_REQUEST_SENSE:
 457+ {
 458+ tb.sense_data.ResponseCode = 0x70;
 459+ tb.sense_data.Obsolete = 0;
 460+ tb.sense_data.fei_sensekey = cur_sense_data.sense_key & 0x0f;
 461+ tb.sense_data.Information = cur_sense_data.information;
 462+ tb.sense_data.AdditionalSenseLength = 10;
 463+ tb.sense_data.CommandSpecificInformation = 0;
 464+ tb.sense_data.AdditionalSenseCode = cur_sense_data.asc;
 465+ tb.sense_data.AdditionalSenseCodeQualifier = cur_sense_data.ascq;
 466+ tb.sense_data.FieldReplaceableUnitCode = 0;
 467+ tb.sense_data.SKSV = 0;
 468+ tb.sense_data.SenseKeySpecific = 0;
 469+ send_command_result(&tb.sense_data, MIN(sizeof(tb.sense_data), length));
 470+ break;
 471+ }
 472+
 473+ case SCSI_MODE_SENSE_10:
 474+ {
 475+ if (ejected)
 476+ {
 477+ send_command_failed_result();
 478+ cur_sense_data.sense_key = SENSE_NOT_READY;
 479+ cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 480+ cur_sense_data.ascq = 0;
 481+ break;
 482+ }
 483+ unsigned char page_code = cbw->command_block[2] & 0x3f;
 484+ switch (page_code)
 485+ {
 486+ case 0x3f:
 487+ tb.ms_data_10.mode_data_length = htobe16(sizeof(tb.ms_data_10) - 2);
 488+ tb.ms_data_10.medium_type = 0;
 489+ tb.ms_data_10.device_specific = 0;
 490+ tb.ms_data_10.reserved = 0;
 491+ tb.ms_data_10.longlba = 1;
 492+ tb.ms_data_10.block_descriptor_length = htobe16(sizeof(tb.ms_data_10.block_descriptor));
 493+
 494+ memset(tb.ms_data_10.block_descriptor.reserved, 0, 4);
 495+ memset(tb.ms_data_10.block_descriptor.num_blocks, 0, 8);
 496+
 497+ tb.ms_data_10.block_descriptor.num_blocks[4] = (RAMDISK_SECTORS & 0xff000000) >> 24;
 498+ tb.ms_data_10.block_descriptor.num_blocks[5] = (RAMDISK_SECTORS & 0x00ff0000) >> 16;
 499+ tb.ms_data_10.block_descriptor.num_blocks[6] = (RAMDISK_SECTORS & 0x0000ff00) >> 8;
 500+ tb.ms_data_10.block_descriptor.num_blocks[7] = (RAMDISK_SECTORS & 0x000000ff);
 501+
 502+ tb.ms_data_10.block_descriptor.block_size[0] = (RAMDISK_SECTORSIZE & 0xff000000) >> 24;
 503+ tb.ms_data_10.block_descriptor.block_size[1] = (RAMDISK_SECTORSIZE & 0x00ff0000) >> 16;
 504+ tb.ms_data_10.block_descriptor.block_size[2] = (RAMDISK_SECTORSIZE & 0x0000ff00) >> 8;
 505+ tb.ms_data_10.block_descriptor.block_size[3] = (RAMDISK_SECTORSIZE & 0x000000ff);
 506+ send_command_result(&tb.ms_data_10, MIN(sizeof(tb.ms_data_10), length));
 507+ break;
 508+ default:
 509+ send_command_failed_result();
 510+ cur_sense_data.sense_key = SENSE_ILLEGAL_REQUEST;
 511+ cur_sense_data.asc = ASC_INVALID_FIELD_IN_CBD;
 512+ cur_sense_data.ascq = 0;
 513+ break;
 514+ }
 515+ break;
 516+ }
 517+
 518+ case SCSI_MODE_SENSE_6:
 519+ {
 520+ if (ejected)
 521+ {
 522+ send_command_failed_result();
 523+ cur_sense_data.sense_key = SENSE_NOT_READY;
 524+ cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 525+ cur_sense_data.ascq = 0;
 526+ break;
 527+ }
 528+ unsigned char page_code = cbw->command_block[2] & 0x3f;
 529+ switch (page_code)
 530+ {
 531+ case 0x3f:
 532+ tb.ms_data_6.mode_data_length = sizeof(tb.ms_data_6) - 1;
 533+ tb.ms_data_6.medium_type = 0;
 534+ tb.ms_data_6.device_specific = 0;
 535+ tb.ms_data_6.block_descriptor_length = sizeof(tb.ms_data_6.block_descriptor);
 536+ tb.ms_data_6.block_descriptor.density_code = 0;
 537+ tb.ms_data_6.block_descriptor.reserved = 0;
 538+ if (RAMDISK_SECTORS > 0xffffff)
 539+ {
 540+ tb.ms_data_6.block_descriptor.num_blocks[0] = 0xff;
 541+ tb.ms_data_6.block_descriptor.num_blocks[1] = 0xff;
 542+ tb.ms_data_6.block_descriptor.num_blocks[2] = 0xff;
 543+ }
 544+ else
 545+ {
 546+ tb.ms_data_6.block_descriptor.num_blocks[0] = (RAMDISK_SECTORS & 0xff0000) >> 16;
 547+ tb.ms_data_6.block_descriptor.num_blocks[1] = (RAMDISK_SECTORS & 0x00ff00) >> 8;
 548+ tb.ms_data_6.block_descriptor.num_blocks[2] = (RAMDISK_SECTORS & 0x0000ff);
 549+ }
 550+ tb.ms_data_6.block_descriptor.block_size[0] = (RAMDISK_SECTORSIZE & 0xff0000) >> 16;
 551+ tb.ms_data_6.block_descriptor.block_size[1] = (RAMDISK_SECTORSIZE & 0x00ff00) >> 8;
 552+ tb.ms_data_6.block_descriptor.block_size[2] = (RAMDISK_SECTORSIZE & 0x0000ff);
 553+ send_command_result(&tb.ms_data_6, MIN(sizeof(tb.ms_data_6), length));
 554+ break;
 555+ default:
 556+ send_command_failed_result();
 557+ cur_sense_data.sense_key = SENSE_ILLEGAL_REQUEST;
 558+ cur_sense_data.asc = ASC_INVALID_FIELD_IN_CBD;
 559+ cur_sense_data.ascq = 0;
 560+ break;
 561+ }
 562+ break;
 563+ }
 564+
 565+ case SCSI_START_STOP_UNIT:
 566+ if ((cbw->command_block[4] & 0xf3) == 2) ejected = true;
 567+ send_csw(0);
 568+ break;
 569+
 570+ case SCSI_ALLOW_MEDIUM_REMOVAL:
 571+ if ((cbw->command_block[4] & 0x03) == 0) locked = false;
 572+ else locked = true;
 573+ send_csw(0);
 574+ break;
 575+
 576+ case SCSI_READ_FORMAT_CAPACITY:
 577+ {
 578+ if (!ejected)
 579+ {
 580+ tb.format_capacity_data.following_length = 0x08000000;
 581+ tb.format_capacity_data.block_count = htobe32(RAMDISK_SECTORS - 1);
 582+ tb.format_capacity_data.block_size = htobe32(RAMDISK_SECTORSIZE);
 583+ tb.format_capacity_data.block_size |= htobe32(SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA);
 584+ send_command_result(&tb.format_capacity_data, MIN(sizeof(tb.format_capacity_data), length));
 585+ }
 586+ else
 587+ {
 588+ send_command_failed_result();
 589+ cur_sense_data.sense_key = SENSE_NOT_READY;
 590+ cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 591+ cur_sense_data.ascq = 0;
 592+ }
 593+ break;
 594+ }
 595+
 596+ case SCSI_READ_CAPACITY:
 597+ {
 598+ if (!ejected)
 599+ {
 600+ tb.capacity_data.block_count = htobe32(RAMDISK_SECTORS - 1);
 601+ tb.capacity_data.block_size = htobe32(RAMDISK_SECTORSIZE);
 602+ send_command_result(&tb.capacity_data, MIN(sizeof(tb.capacity_data), length));
 603+ }
 604+ else
 605+ {
 606+ send_command_failed_result();
 607+ cur_sense_data.sense_key = SENSE_NOT_READY;
 608+ cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 609+ cur_sense_data.ascq = 0;
 610+ }
 611+ break;
 612+ }
 613+
 614+ case SCSI_READ_10:
 615+ if (ejected)
 616+ {
 617+ send_command_failed_result();
 618+ cur_sense_data.sense_key = SENSE_NOT_READY;
 619+ cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 620+ cur_sense_data.ascq = 0;
 621+ break;
 622+ }
 623+ cur_cmd.sector = (cbw->command_block[2] << 24 | cbw->command_block[3] << 16
 624+ | cbw->command_block[4] << 8 | cbw->command_block[5]);
 625+ cur_cmd.count = (cbw->command_block[7] << 8 | cbw->command_block[8]);
 626+ cur_cmd.orig_count = cur_cmd.count;
 627+
 628+ if ((cur_cmd.sector + cur_cmd.count) > RAMDISK_SECTORS)
 629+ {
 630+ send_csw(1);
 631+ cur_sense_data.sense_key = SENSE_ILLEGAL_REQUEST;
 632+ cur_sense_data.asc = ASC_LBA_OUT_OF_RANGE;
 633+ cur_sense_data.ascq = 0;
 634+ }
 635+ else send_and_read_next();
 636+ break;
 637+
 638+ case SCSI_WRITE_10:
 639+ if (ejected)
 640+ {
 641+ send_command_failed_result();
 642+ cur_sense_data.sense_key = SENSE_NOT_READY;
 643+ cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 644+ cur_sense_data.ascq = 0;
 645+ break;
 646+ }
 647+ cur_cmd.sector = (cbw->command_block[2] << 24 | cbw->command_block[3] << 16
 648+ | cbw->command_block[4] << 8 | cbw->command_block[5]);
 649+ cur_cmd.count = (cbw->command_block[7] << 8 | cbw->command_block[8]);
 650+ cur_cmd.orig_count = cur_cmd.count;
 651+
 652+ if ((cur_cmd.sector + cur_cmd.count) > RAMDISK_SECTORS)
 653+ {
 654+ send_csw(1);
 655+ cur_sense_data.sense_key = SENSE_ILLEGAL_REQUEST;
 656+ cur_sense_data.asc = ASC_LBA_OUT_OF_RANGE;
 657+ cur_sense_data.ascq = 0;
 658+ }
 659+ else
 660+ receive_block_data(ramdisk[cur_cmd.sector], MIN(maxlen, cur_cmd.count * RAMDISK_SECTORSIZE));
 661+ break;
 662+
 663+ case SCSI_WRITE_BUFFER:
 664+ break;
 665+
 666+ default:
 667+ send_csw(1);
 668+ cur_sense_data.sense_key = SENSE_ILLEGAL_REQUEST;
 669+ cur_sense_data.asc = ASC_INVALID_COMMAND;
 670+ cur_sense_data.ascq = 0;
 671+ break;
 672+ }
 673+}
 674+
 675+int handle_ctrl_request(const struct usb_instance* data, int interface, union usb_ep0_buffer* request, const void** response)
 676+{
 677+ int size = -1;
 678+ switch (request->setup.bmRequestType.type)
 679+ {
 680+ case USB_SETUP_BMREQUESTTYPE_TYPE_CLASS:
 681+ switch (request->setup.bRequest.raw)
 682+ {
 683+ case 0xfe: // GET_MAX_LUN
 684+ data->buffer->raw[0] = 0;
 685+ size = 1;
 686+ break;
 687+ case 0xff: // STORAGE_RESET
 688+ size = 0;
 689+ break;
 690+ default: break;
 691+ }
 692+ break;
 693+ default: break;
 694+ }
 695+ return size;
 696+}
 697+
 698+void handle_set_altsetting(const struct usb_instance* data, int interface, int altsetting)
 699+{
 700+ usb = data;
 701+ state = WAITING_FOR_COMMAND;
 702+ maxlen = maxpacket * MIN(usb_get_max_transfer_size(usb, outep), usb_get_max_transfer_size(usb, inep));
 703+ usb_configure_ep(usb, outep, USB_ENDPOINT_TYPE_BULK, maxpacket);
 704+ usb_configure_ep(usb, inep, USB_ENDPOINT_TYPE_BULK, maxpacket);
 705+ listen();
 706+}
 707+
 708+void handle_unset_altsetting(const struct usb_instance* data, int interface, int altsetting)
 709+{
 710+ usb_unconfigure_ep(usb, outep);
 711+ usb_unconfigure_ep(usb, inep);
 712+}
 713+
 714+int handle_ep_ctrl_request(const struct usb_instance* data, int interface, int endpoint, union usb_ep0_buffer* request, const void** response)
 715+{
 716+ int size = -1;
 717+ switch (request->setup.bmRequestType.type)
 718+ {
 719+ case USB_SETUP_BMREQUESTTYPE_TYPE_STANDARD:
 720+ switch (request->setup.bRequest.req)
 721+ {
 722+ case USB_SETUP_BREQUEST_CLEAR_FEATURE:
 723+ if (request->setup.wLength || request->setup.wValue) break;
 724+ listen();
 725+ break;
 726+ default: break;
 727+ }
 728+ break;
 729+ default: break;
 730+ }
 731+ return size;
 732+}
 733+
 734+void handle_xfer_complete(const struct usb_instance* data, int ifnum, int epnum, int bytesleft)
 735+{
 736+ length -= bytesleft;
 737+ switch (state)
 738+ {
 739+ case RECEIVING_BLOCKS:
 740+ if (length != RAMDISK_SECTORSIZE * cur_cmd.count && length != maxlen) break;
 741+
 742+ cur_cmd.sector += (maxlen / RAMDISK_SECTORSIZE);
 743+ cur_cmd.count -= MIN(cur_cmd.count, maxlen / RAMDISK_SECTORSIZE);
 744+
 745+ if (cur_cmd.count)
 746+ receive_block_data(ramdisk[cur_cmd.sector], MIN(maxlen, cur_cmd.count * RAMDISK_SECTORSIZE));
 747+ else send_csw(0);
 748+ break;
 749+ case WAITING_FOR_CSW_COMPLETION:
 750+ state = WAITING_FOR_COMMAND;
 751+ listen();
 752+ break;
 753+ case WAITING_FOR_COMMAND:
 754+ handle_scsi(&cbw);
 755+ break;
 756+ case SENDING_RESULT:
 757+ send_csw(0);
 758+ break;
 759+ case SENDING_FAILED_RESULT:
 760+ send_csw(1);
 761+ break;
 762+ case SENDING_BLOCKS:
 763+ if (!cur_cmd.count) send_csw(0);
 764+ else send_and_read_next();
 765+ break;
 766+ }
 767+}
 768+
 769+void handle_timeout(const struct usb_instance* data, int interface, int endpoint, int bytesleft)
 770+{
 771+ usb_set_stall(usb, outep, true);
 772+ usb_set_stall(usb, inep, true);
 773+}
 774+
 775+static void handle_bus_reset(const struct usb_instance* data, int configuration, int interface, int highspeed)
 776+{
 777+ maxpacket = highspeed ? 512 : 64;
 778+ usb_config1_descriptors.c1_i0_a0_e1out.wMaxPacketSize = maxpacket;
 779+ usb_config1_descriptors.c1_i0_a0_e1in.wMaxPacketSize = maxpacket;
 780+}
 781+
 782+static struct usb_endpoint usb_c1_i0_a0_ep1out =
 783+{
 784+ .number = { .number = 0, .direction = USB_ENDPOINT_DIRECTION_OUT },
 785+ .ctrl_request = handle_ep_ctrl_request,
 786+ .xfer_complete = handle_xfer_complete,
 787+};
 788+
 789+static struct usb_endpoint usb_c1_i0_a0_ep1in =
 790+{
 791+ .number = { .number = 0, .direction = USB_ENDPOINT_DIRECTION_IN },
 792+ .ctrl_request = handle_ep_ctrl_request,
 793+ .xfer_complete = handle_xfer_complete,
 794+ .timeout = handle_timeout,
 795+};
 796+
 797+static const struct usb_altsetting usb_c1_i0_a0 =
 798+{
 799+ .set_altsetting = handle_set_altsetting,
 800+ .unset_altsetting = handle_unset_altsetting,
 801+ .endpoint_count = 2,
 802+ .endpoints =
 803+ {
 804+ &usb_c1_i0_a0_ep1out,
 805+ &usb_c1_i0_a0_ep1in,
 806+ },
 807+};
 808+
 809+static const struct usb_interface usb_c1_i0 =
 810+{
 811+ .bus_reset = handle_bus_reset,
 812+ .ctrl_request = handle_ctrl_request,
 813+ .altsetting_count = 1,
 814+ .altsettings =
 815+ {
 816+ &usb_c1_i0_a0,
 817+ },
 818+};
 819+
 820+static const struct usb_configuration usb_c1 =
 821+{
 822+ .descriptor = &usb_config1_descriptors.c1,
 823+ .set_configuration = NULL,
 824+ .unset_configuration = NULL,
 825+ .interface_count = 1,
 826+ .interfaces =
 827+ {
 828+ &usb_c1_i0,
 829+ },
 830+};
 831+
 832+static const struct usb_configuration* usb_configurations[] =
 833+{
 834+ &usb_c1,
 835+};
 836+
 837+static void main(int argc, const char** argv)
 838+{
 839+ int i;
 840+ uint32_t eps = usbmanager_get_available_endpoints();
 841+ int ep_out = 0;
 842+ int ep_in = 0;
 843+ for (i = 1; i < 16; i++)
 844+ if (eps & (1 << i))
 845+ {
 846+ ep_out = i;
 847+ break;
 848+ }
 849+ for (i = 1; i < 16; i++)
 850+ if (eps & (1 << (16 + i)))
 851+ {
 852+ ep_in = i;
 853+ break;
 854+ }
 855+ if (!ep_out || !ep_in) panicf(PANIC_KILLTHREAD, "Not enough USB endpoints available!\n");
 856+ usb_config1_descriptors.c1_i0_a0_e1out.bEndpointAddress.number = ep_out;
 857+ usb_config1_descriptors.c1_i0_a0_e1in.bEndpointAddress.number = ep_in;
 858+ usb_c1_i0_a0_ep1out.number.number = ep_out;
 859+ usb_c1_i0_a0_ep1in.number.number = ep_in;
 860+ outep.number = ep_out;
 861+ inep.number = ep_in;
 862+ int rc = usbmanager_install_custom(&usb_devicedescriptor, ARRAYLEN(usb_configurations), usb_configurations,
 863+ ARRAYLEN(usb_stringdescriptors), usb_stringdescriptors, true);
 864+ if (IS_ERR(rc)) panicf(PANIC_KILLTHREAD, "Failed to register USB handler: %08X\n", rc);
 865+ while (!ejected && usbmanager_get_connected()) sleep(200000);
 866+ usbmanager_uninstall_custom();
 867+}
 868+
 869+
 870+EMCORE_APP_HEADER("USB mass storage test", main, 127)
 871+
Index: apps/umstest/version.h
@@ -0,0 +1,36 @@
 2+//
 3+//
 4+// Copyright 2010 TheSeven
 5+//
 6+//
 7+// This file is part of emCORE.
 8+//
 9+// emCORE is free software: you can redistribute it and/or
 10+// modify it under the terms of the GNU General Public License as
 11+// published by the Free Software Foundation, either version 2 of the
 12+// License, or (at your option) any later version.
 13+//
 14+// emCORE is distributed in the hope that it will be useful,
 15+// but WITHOUT ANY WARRANTY; without even the implied warranty of
 16+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 17+// See the GNU General Public License for more details.
 18+//
 19+// You should have received a copy of the GNU General Public License along
 20+// with emCORE. If not, see <http://www.gnu.org/licenses/>.
 21+//
 22+//
 23+
 24+
 25+#ifndef __VERSION_H__
 26+#define __VERSION_H__
 27+
 28+
 29+#define VERSION "0.0.1pre"
 30+#define VERSION_MAJOR 0
 31+#define VERSION_MINOR 0
 32+#define VERSION_PATCH 1
 33+#define VERSION_SVN "$REVISION$"
 34+#define VERSION_SVN_INT $REVISIONINT$
 35+
 36+
 37+#endif
\ No newline at end of file
Index: apps/umstest/Makefile
@@ -0,0 +1,120 @@
 2+NAME := umstest
 3+STACKSIZE := 4096
 4+COMPRESS := true
 5+
 6+EMCOREDIR ?= ../../emcore/trunk/
 7+
 8+ifeq ($(shell uname),WindowsNT)
 9+CCACHE :=
 10+else
 11+CCACHE := $(shell which ccache)
 12+endif
 13+
 14+CROSS ?= arm-elf-eabi-
 15+CC := $(CCACHE) $(CROSS)gcc
 16+AS := $(CROSS)as
 17+LD := $(CROSS)ld
 18+OBJCOPY := $(CROSS)objcopy
 19+ELF2ECA := $(CROSS)elf2emcoreapp
 20+
 21+LIBINCLUDES :=
 22+
 23+CFLAGS += -Os -fno-pie -fno-stack-protector -fomit-frame-pointer -I. -I$(EMCOREDIR)/export $(LIBINCLUDES) -ffunction-sections -fdata-sections -mcpu=arm940t -DARM_ARCH=4 -marm
 24+LDFLAGS += "$(shell $(CC) -print-libgcc-file-name)" --emit-relocs --gc-sections
 25+
 26+preprocess = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#")
 27+preprocesspaths = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#" | sed -e "s:^..*:$(dir $(1))&:" | sed -e "s:^\\./::")
 28+
 29+REVISION := $(shell svnversion .)
 30+REVISIONINT := $(shell echo $(REVISION) | sed -e "s/[^0-9].*$$//")
 31+
 32+HELPERS := build/__emcore_armhelpers.o
 33+
 34+SRC := $(call preprocesspaths,SOURCES,-I. -I..)
 35+OBJ := $(SRC:%.c=build/%.o)
 36+OBJ := $(OBJ:%.S=build/%.o) $(HELPERS)
 37+
 38+all: $(NAME)
 39+
 40+-include $(OBJ:%=%.dep)
 41+
 42+$(NAME): build/$(NAME).emcoreapp
 43+
 44+build/$(NAME).emcoreapp: build/$(NAME).elf
 45+ @echo [EMCAPP] $<
 46+ifeq ($(COMPRESS),true)
 47+ @$(ELF2ECA) -z -s $(STACKSIZE) -o $@ $^
 48+else
 49+ @$(ELF2ECA) -s $(STACKSIZE) -o $@ $^
 50+endif
 51+
 52+build/$(NAME).elf: ls.x $(OBJ)
 53+ @echo [LD] $@
 54+ @$(LD) $(LDFLAGS) -o $@ -T ls.x $(OBJ)
 55+
 56+build/%.o: %.c build/version.h
 57+ @echo [CC] $<
 58+ifeq ($(shell uname),WindowsNT)
 59+ @-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
 60+else
 61+ @-mkdir -p $(dir $@)
 62+endif
 63+ @$(CC) -c $(CFLAGS) -o $@ $<
 64+ @$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
 65+ @sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
 66+ifeq ($(shell uname),WindowsNT)
 67+ @sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
 68+else
 69+ @sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
 70+endif
 71+ @rm -f $@.dep.tmp
 72+
 73+build/%.o: %.S build/version.h
 74+ @echo [CC] $<
 75+ifeq ($(shell uname),WindowsNT)
 76+ @-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
 77+else
 78+ @-mkdir -p $(dir $@)
 79+endif
 80+ @$(CC) -c $(CFLAGS) -o $@ $<
 81+ @$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
 82+ @sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
 83+ifeq ($(shell uname),WindowsNT)
 84+ @sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
 85+else
 86+ @sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
 87+endif
 88+ @rm -f $@.dep.tmp
 89+
 90+build/__emcore_%.o: $(EMCOREDIR)/export/%.c
 91+ @echo [CC] $<
 92+ifeq ($(shell uname),WindowsNT)
 93+ @-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
 94+else
 95+ @-mkdir -p $(dir $@)
 96+endif
 97+ @$(CC) -c $(CFLAGS) -o $@ $<
 98+
 99+build/__emcore_%.o: $(EMCOREDIR)/export/%.S
 100+ @echo [CC] $<
 101+ifeq ($(shell uname),WindowsNT)
 102+ @-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
 103+else
 104+ @-mkdir -p $(dir $@)
 105+endif
 106+ @$(CC) -c $(CFLAGS) -o $@ $<
 107+
 108+build/version.h: version.h ../../.svn/entries
 109+ @echo [PP] $<
 110+ifeq ($(shell uname),WindowsNT)
 111+ @-if not exist build md build
 112+ @sed -e "s/\$$REVISION\$$/$(REVISION)/" -e "s/\$$REVISIONINT\$$/$(REVISIONINT)/" < $< > $@
 113+else
 114+ @-mkdir -p build
 115+ @sed -e 's/\$$REVISION\$$/$(REVISION)/' -e 's/\$$REVISIONINT\$$/$(REVISIONINT)/' < $< > $@
 116+endif
 117+
 118+clean:
 119+ @rm -rf build
 120+
 121+.PHONY: all clean $(NAME)
Index: apps/umstest/SOURCES
@@ -0,0 +1 @@
 2+main.c
Index: apps/umstest/ls.x
@@ -0,0 +1,42 @@
 2+ENTRY(__emcore_entrypoint)
 3+OUTPUT_FORMAT(elf32-littlearm)
 4+OUTPUT_ARCH(arm)
 5+
 6+MEMORY
 7+{
 8+ VIRTUAL : ORIGIN = 0x00000000, LENGTH = 0x10000000
 9+}
 10+
 11+SECTIONS
 12+{
 13+ .text :
 14+ {
 15+ __emcore_app_base = .;
 16+ KEEP(.emcoreentrypoint*)
 17+ *(.emcoreentrypoint*)
 18+ *(.text*)
 19+ *(.glue_7)
 20+ *(.glue_7t)
 21+ . = ALIGN(0x10);
 22+ } > VIRTUAL
 23+
 24+ .data :
 25+ {
 26+ *(.rodata*)
 27+ . = ALIGN(0x4);
 28+ *(.data*)
 29+ . = ALIGN(0x10);
 30+ } > VIRTUAL
 31+
 32+ .bss (NOLOAD) :
 33+ {
 34+ *(.bss*)
 35+ *(COMMON)
 36+ } > VIRTUAL
 37+
 38+ /DISCARD/ :
 39+ {
 40+ *(.eh_frame)
 41+ }
 42+
 43+}