reorganise the usb stack to provide a clean separation between core and class drivers
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16541 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
5f83f0e4d2
commit
f0b4a32d6f
10 changed files with 786 additions and 576 deletions
|
@ -102,6 +102,10 @@
|
|||
#include "as3514.h"
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_USBSTACK) && defined(ROCKBOX_HAS_LOGF)
|
||||
#include "usb_core.h"
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/* SPECIAL DEBUG STUFF */
|
||||
/*---------------------------------------------------*/
|
||||
|
@ -2364,13 +2368,12 @@ static bool dbg_scrollwheel(void)
|
|||
#endif
|
||||
|
||||
#if defined(HAVE_USBSTACK) && defined(ROCKBOX_HAS_LOGF)
|
||||
extern bool usb_core_serial_enabled;
|
||||
|
||||
static bool logf_usb_serial(void)
|
||||
{
|
||||
usb_core_serial_enabled = !usb_core_serial_enabled;
|
||||
bool serial_enabled = !usb_core_driver_enabled(USB_DRIVER_SERIAL);
|
||||
usb_core_enable_driver(USB_DRIVER_SERIAL,serial_enabled);
|
||||
gui_syncsplash(HZ, "USB logf %s",
|
||||
usb_core_serial_enabled?"enabled":"disabled");
|
||||
serial_enabled?"enabled":"disabled");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -24,13 +24,13 @@
|
|||
|
||||
/* Messages from usb_tick and thread states */
|
||||
enum {
|
||||
USB_INSERTED,
|
||||
USB_EXTRACTED,
|
||||
USB_REENABLE,
|
||||
USB_POWERED,
|
||||
USB_TRANSFER_COMPLETION,
|
||||
USB_REQUEST_DISK,
|
||||
USB_REQUEST_REBOOT
|
||||
USB_INSERTED,
|
||||
USB_EXTRACTED,
|
||||
USB_REENABLE,
|
||||
USB_POWERED,
|
||||
USB_TRANSFER_COMPLETION,
|
||||
USB_REQUEST_DISK,
|
||||
USB_REQUEST_REBOOT
|
||||
};
|
||||
|
||||
|
||||
|
@ -69,7 +69,8 @@ enum {
|
|||
enum {
|
||||
USB_DRIVER_MASS_STORAGE,
|
||||
USB_DRIVER_SERIAL,
|
||||
USB_DRIVER_CHARGING_ONLY
|
||||
USB_DRIVER_CHARGING_ONLY,
|
||||
USB_NUM_DRIVERS
|
||||
};
|
||||
#endif
|
||||
#ifdef HAVE_USBSTACK
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#ifndef BOOTLOADER
|
||||
|
||||
//#define USB_SERIAL
|
||||
#define USB_SERIAL
|
||||
#define USB_STORAGE
|
||||
#define USB_CHARGING_ONLY
|
||||
#else /* BOOTLOADER */
|
||||
|
@ -32,19 +32,8 @@
|
|||
#include "usb.h"
|
||||
|
||||
/* endpoints */
|
||||
enum {
|
||||
EP_CONTROL = 0,
|
||||
#ifdef USB_STORAGE
|
||||
EP_MASS_STORAGE,
|
||||
#endif
|
||||
#ifdef USB_SERIAL
|
||||
EP_SERIAL,
|
||||
#endif
|
||||
#ifdef USB_CHARGING_ONLY
|
||||
EP_CHARGING_ONLY,
|
||||
#endif
|
||||
NUM_ENDPOINTS
|
||||
};
|
||||
#define EP_CONTROL 0
|
||||
#define NUM_ENDPOINTS 3
|
||||
|
||||
extern int usb_max_pkt_size;
|
||||
|
||||
|
@ -54,7 +43,9 @@ void usb_core_control_request(struct usb_ctrlrequest* req);
|
|||
void usb_core_transfer_complete(int endpoint, bool in, int status, int length);
|
||||
void usb_core_bus_reset(void);
|
||||
bool usb_core_exclusive_connection(void);
|
||||
void usb_core_enable_protocol(int driver,bool enabled);
|
||||
void usb_core_handle_transfer_completion(struct usb_transfer_completion_event_data* event);
|
||||
void usb_core_enable_driver(int driver,bool enabled);
|
||||
bool usb_core_driver_enabled (int driver);
|
||||
void usb_core_handle_transfer_completion(
|
||||
struct usb_transfer_completion_event_data* event);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -191,8 +191,8 @@ static void usb_thread(void)
|
|||
{
|
||||
usb_state = USB_POWERED;
|
||||
#ifdef HAVE_USBSTACK
|
||||
usb_core_enable_protocol(USB_DRIVER_MASS_STORAGE,false);
|
||||
usb_core_enable_protocol(USB_DRIVER_CHARGING_ONLY,true);
|
||||
usb_core_enable_driver(USB_DRIVER_MASS_STORAGE,false);
|
||||
usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY,true);
|
||||
usb_enable(true);
|
||||
#endif
|
||||
}
|
||||
|
@ -200,8 +200,8 @@ static void usb_thread(void)
|
|||
#endif
|
||||
{
|
||||
#ifdef HAVE_USBSTACK
|
||||
usb_core_enable_protocol(USB_DRIVER_MASS_STORAGE,true);
|
||||
usb_core_enable_protocol(USB_DRIVER_CHARGING_ONLY,false);
|
||||
usb_core_enable_driver(USB_DRIVER_MASS_STORAGE,true);
|
||||
usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY,false);
|
||||
usb_enable(true);
|
||||
#else
|
||||
/* Tell all threads that they have to back off the ATA.
|
||||
|
|
59
firmware/usbstack/usb_class_driver.h
Normal file
59
firmware/usbstack/usb_class_driver.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id: $
|
||||
*
|
||||
* Copyright (C) 2008 Frank Gevaerts
|
||||
*
|
||||
* All files in this archive are subject to the GNU General Public License.
|
||||
* See the file COPYING in the source tree root for full license agreement.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _USB_CLASS_DRIVER_H_
|
||||
#define _USB_CLASS_DRIVER_H_
|
||||
|
||||
/* Common api, implemented by all class drivers */
|
||||
|
||||
struct usb_class_driver {
|
||||
bool enabled;
|
||||
bool needs_exclusive_ata;
|
||||
int usb_endpoint;
|
||||
int usb_interface;
|
||||
|
||||
/* Asks the driver to put the interface descriptor and all other
|
||||
needed descriptor for this driver at dest, for the given settings.
|
||||
Returns the number of bytes taken by these descriptors. */
|
||||
int (*get_config_descriptor)(unsigned char *dest,
|
||||
int max_packet_size, int interface_number, int endpoint);
|
||||
|
||||
/* Tells the driver that a usb connection has been set up and is now
|
||||
ready to use. */
|
||||
void (*init_connection)(int interface,int endpoint);
|
||||
|
||||
/* Initialises the driver. This can be called multiple times,
|
||||
and should not perform any action that can disturb other threads
|
||||
(like getting the audio buffer) */
|
||||
void (*init)(void);
|
||||
|
||||
/* Tells the driver that the usb connection is no longer active */
|
||||
void (*disconnect)(void);
|
||||
|
||||
/* Tells the driver that a usb transfer has been completed. Note that "in"
|
||||
is relative to the host */
|
||||
void (*transfer_complete)(bool in, int status, int length);
|
||||
|
||||
/* Tells the driver that a control request has come in. If the driver is
|
||||
able to handle it, it should ack the request, and return true. Otherwise
|
||||
it should return false. */
|
||||
bool (*control_request)(struct usb_ctrlrequest* req);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -27,6 +27,7 @@
|
|||
#include "usb_ch9.h"
|
||||
#include "usb_drv.h"
|
||||
#include "usb_core.h"
|
||||
#include "usb_class_driver.h"
|
||||
|
||||
#if defined(USB_STORAGE)
|
||||
#include "usb_storage.h"
|
||||
|
@ -36,7 +37,7 @@
|
|||
#include "usb_serial.h"
|
||||
#endif
|
||||
|
||||
/* TODO: Move this target-specific stuff somewhere else (serial number reading) */
|
||||
/* TODO: Move target-specific stuff somewhere else (serial number reading) */
|
||||
|
||||
#ifdef HAVE_AS3514
|
||||
#include "i2c-pp.h"
|
||||
|
@ -54,7 +55,9 @@
|
|||
#define USB_SC_SCSI 0x06 /* Transparent */
|
||||
#define USB_PROT_BULK 0x50 /* bulk only */
|
||||
|
||||
static const struct usb_device_descriptor __attribute__((aligned(2))) device_descriptor= {
|
||||
static const struct usb_device_descriptor __attribute__((aligned(2)))
|
||||
device_descriptor=
|
||||
{
|
||||
.bLength = sizeof(struct usb_device_descriptor),
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
#ifdef USE_HIGH_SPEED
|
||||
|
@ -75,7 +78,8 @@ static const struct usb_device_descriptor __attribute__((aligned(2))) device_des
|
|||
.bNumConfigurations = 1
|
||||
} ;
|
||||
|
||||
struct usb_config_descriptor __attribute__((aligned(2))) config_descriptor =
|
||||
static struct usb_config_descriptor __attribute__((aligned(2)))
|
||||
config_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_config_descriptor),
|
||||
.bDescriptorType = USB_DT_CONFIG,
|
||||
|
@ -89,7 +93,8 @@ struct usb_config_descriptor __attribute__((aligned(2))) config_descriptor =
|
|||
|
||||
#ifdef USB_CHARGING_ONLY
|
||||
/* dummy interface for charging-only */
|
||||
struct usb_interface_descriptor __attribute__((aligned(2))) charging_interface_descriptor =
|
||||
static struct usb_interface_descriptor __attribute__((aligned(2)))
|
||||
charging_interface_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
|
@ -103,77 +108,8 @@ struct usb_interface_descriptor __attribute__((aligned(2))) charging_interface_d
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef USB_STORAGE
|
||||
/* storage interface */
|
||||
struct usb_interface_descriptor __attribute__((aligned(2))) mass_storage_interface_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
|
||||
.bInterfaceSubClass = USB_SC_SCSI,
|
||||
.bInterfaceProtocol = USB_PROT_BULK,
|
||||
.iInterface = 0
|
||||
};
|
||||
|
||||
struct usb_endpoint_descriptor __attribute__((aligned(2))) mass_storage_ep_in_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_MASS_STORAGE | USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 16,
|
||||
.bInterval = 0
|
||||
};
|
||||
struct usb_endpoint_descriptor __attribute__((aligned(2))) mass_storage_ep_out_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_MASS_STORAGE | USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 16,
|
||||
.bInterval = 0
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef USB_SERIAL
|
||||
/* serial interface */
|
||||
struct usb_interface_descriptor __attribute__((aligned(2))) serial_interface_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = 0
|
||||
};
|
||||
|
||||
struct usb_endpoint_descriptor __attribute__((aligned(2))) serial_ep_in_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_SERIAL | USB_DIR_IN,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 16,
|
||||
.bInterval = 0
|
||||
};
|
||||
struct usb_endpoint_descriptor __attribute__((aligned(2))) serial_ep_out_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = EP_SERIAL | USB_DIR_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 16,
|
||||
.bInterval = 0
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct usb_qualifier_descriptor __attribute__((aligned(2))) qualifier_descriptor =
|
||||
static const struct usb_qualifier_descriptor __attribute__((aligned(2)))
|
||||
qualifier_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_qualifier_descriptor),
|
||||
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
|
||||
|
@ -185,21 +121,26 @@ static const struct usb_qualifier_descriptor __attribute__((aligned(2))) qualifi
|
|||
.bNumConfigurations = 1
|
||||
};
|
||||
|
||||
static struct usb_string_descriptor __attribute__((aligned(2))) usb_string_iManufacturer =
|
||||
static struct usb_string_descriptor __attribute__((aligned(2)))
|
||||
usb_string_iManufacturer =
|
||||
{
|
||||
24,
|
||||
USB_DT_STRING,
|
||||
{'R','o','c','k','b','o','x','.','o','r','g'}
|
||||
};
|
||||
|
||||
static struct usb_string_descriptor __attribute__((aligned(2))) usb_string_iProduct =
|
||||
static struct usb_string_descriptor __attribute__((aligned(2)))
|
||||
usb_string_iProduct =
|
||||
{
|
||||
42,
|
||||
USB_DT_STRING,
|
||||
{'R','o','c','k','b','o','x',' ','m','e','d','i','a',' ','p','l','a','y','e','r'}
|
||||
{'R','o','c','k','b','o','x',' ',
|
||||
'm','e','d','i','a',' ',
|
||||
'p','l','a','y','e','r'}
|
||||
};
|
||||
|
||||
static struct usb_string_descriptor __attribute__((aligned(2))) usb_string_iSerial =
|
||||
static struct usb_string_descriptor __attribute__((aligned(2)))
|
||||
usb_string_iSerial =
|
||||
{
|
||||
84,
|
||||
USB_DT_STRING,
|
||||
|
@ -211,14 +152,16 @@ static struct usb_string_descriptor __attribute__((aligned(2))) usb_string_iSeri
|
|||
/* Generic for all targets */
|
||||
|
||||
/* this is stringid #0: languages supported */
|
||||
static struct usb_string_descriptor __attribute__((aligned(2))) lang_descriptor =
|
||||
static struct usb_string_descriptor __attribute__((aligned(2)))
|
||||
lang_descriptor =
|
||||
{
|
||||
4,
|
||||
USB_DT_STRING,
|
||||
{0x0409} /* LANGID US English */
|
||||
};
|
||||
|
||||
static struct usb_string_descriptor __attribute__((aligned(2))) usb_string_charging_only =
|
||||
static struct usb_string_descriptor __attribute__((aligned(2)))
|
||||
usb_string_charging_only =
|
||||
{
|
||||
28,
|
||||
USB_DT_STRING,
|
||||
|
@ -238,14 +181,56 @@ static int usb_address = 0;
|
|||
static bool initialized = false;
|
||||
static enum { DEFAULT, ADDRESS, CONFIGURED } usb_state;
|
||||
|
||||
static int usb_core_num_interfaces;
|
||||
|
||||
int usb_charging_get_config_descriptor(unsigned char *dest,int max_packet_size,
|
||||
int interface_number,int endpoint);
|
||||
|
||||
struct usb_class_driver drivers[] =
|
||||
{
|
||||
#ifdef USB_STORAGE
|
||||
static bool usb_core_storage_enabled = false;
|
||||
[USB_DRIVER_MASS_STORAGE] = {
|
||||
.enabled = false,
|
||||
.needs_exclusive_ata = true,
|
||||
.usb_endpoint = 0,
|
||||
.usb_interface = 0,
|
||||
.get_config_descriptor = usb_storage_get_config_descriptor,
|
||||
.init_connection = usb_storage_init_connection,
|
||||
.init = usb_storage_init,
|
||||
.disconnect = NULL,
|
||||
.transfer_complete = usb_storage_transfer_complete,
|
||||
.control_request = usb_storage_control_request
|
||||
},
|
||||
#endif
|
||||
#ifdef USB_SERIAL
|
||||
[USB_DRIVER_SERIAL] = {
|
||||
.enabled = false,
|
||||
.needs_exclusive_ata = false,
|
||||
.usb_endpoint = 0,
|
||||
.usb_interface = 0,
|
||||
.get_config_descriptor = usb_serial_get_config_descriptor,
|
||||
.init_connection = usb_serial_init_connection,
|
||||
.init = usb_serial_init,
|
||||
.disconnect = usb_serial_disconnect,
|
||||
.transfer_complete = usb_serial_transfer_complete,
|
||||
.control_request = usb_serial_control_request
|
||||
},
|
||||
#endif
|
||||
/* Next one is non-static, to enable setting it from the debug menu */
|
||||
bool usb_core_serial_enabled = false;
|
||||
#ifdef USB_CHARGING_ONLY
|
||||
static bool usb_core_charging_enabled = false;
|
||||
[USB_DRIVER_CHARGING_ONLY] = {
|
||||
.enabled = false,
|
||||
.needs_exclusive_ata = false,
|
||||
.usb_endpoint = 0,
|
||||
.usb_interface = 0,
|
||||
.get_config_descriptor = usb_charging_get_config_descriptor,
|
||||
.init_connection = NULL,
|
||||
.init = NULL,
|
||||
.disconnect = NULL,
|
||||
.transfer_complete = NULL,
|
||||
.control_request = NULL
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static void usb_core_control_request_handler(struct usb_ctrlrequest* req);
|
||||
static int ack_control(struct usb_ctrlrequest* req);
|
||||
|
@ -272,11 +257,9 @@ static void set_serial_descriptor(void)
|
|||
uint32_t x;
|
||||
int i,j;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
for (i = 0; i < 2; i++) {
|
||||
x = serial[i];
|
||||
for (j=0;j<8;j++)
|
||||
{
|
||||
for (j=0;j<8;j++) {
|
||||
*p-- = hex[x & 0xf];
|
||||
x >>= 4;
|
||||
}
|
||||
|
@ -292,8 +275,7 @@ static void set_serial_descriptor(void)
|
|||
int i;
|
||||
|
||||
i2c_readbytes(AS3514_I2C_ADDR, 0x30, 0x10, serial);
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
for (i = 0; i < 16; i++) {
|
||||
*p++ = hex[(serial[i] >> 4) & 0xF];
|
||||
*p++ = hex[(serial[i] >> 0) & 0xF];
|
||||
}
|
||||
|
@ -309,8 +291,7 @@ static void set_serial_descriptor(void)
|
|||
unsigned short x;
|
||||
int i;
|
||||
|
||||
for (i = 10; i < 20; i++)
|
||||
{
|
||||
for (i = 10; i < 20; i++) {
|
||||
x = identify[i];
|
||||
*p++ = hex[(x >> 12) & 0xF];
|
||||
*p++ = hex[(x >> 8) & 0xF];
|
||||
|
@ -323,6 +304,7 @@ static void set_serial_descriptor(void)
|
|||
|
||||
void usb_core_init(void)
|
||||
{
|
||||
int i;
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
|
@ -333,27 +315,34 @@ void usb_core_init(void)
|
|||
/* class driver init functions should be safe to call even if the driver
|
||||
* won't be used. This simplifies other logic (i.e. we don't need to know
|
||||
* yet which drivers will be enabled */
|
||||
#ifdef USB_STORAGE
|
||||
if(usb_core_storage_enabled)
|
||||
usb_storage_init();
|
||||
#endif
|
||||
|
||||
#ifdef USB_SERIAL
|
||||
if(usb_core_serial_enabled)
|
||||
usb_serial_init();
|
||||
#endif
|
||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||
if(drivers[i].enabled && drivers[i].init != NULL)
|
||||
drivers[i].init();
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
usb_state = DEFAULT;
|
||||
logf("usb_core_init() finished");
|
||||
}
|
||||
|
||||
int usb_charging_get_config_descriptor(unsigned char *dest,int max_packet_size,
|
||||
int interface_number,int endpoint)
|
||||
{
|
||||
(void) max_packet_size;
|
||||
(void) endpoint;
|
||||
charging_interface_descriptor.bInterfaceNumber=interface_number;
|
||||
memcpy(dest,&charging_interface_descriptor,
|
||||
sizeof(struct usb_interface_descriptor));
|
||||
return sizeof(struct usb_interface_descriptor);
|
||||
}
|
||||
|
||||
void usb_core_exit(void)
|
||||
{
|
||||
#ifdef USB_SERIAL
|
||||
if(usb_core_serial_enabled)
|
||||
usb_serial_exit();
|
||||
#endif
|
||||
int i;
|
||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||
if(drivers[i].enabled && drivers[i].disconnect != NULL)
|
||||
drivers[i].disconnect ();
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
usb_drv_exit();
|
||||
|
@ -362,321 +351,332 @@ void usb_core_exit(void)
|
|||
logf("usb_core_exit() finished");
|
||||
}
|
||||
|
||||
void usb_core_handle_transfer_completion(struct usb_transfer_completion_event_data* event)
|
||||
void usb_core_handle_transfer_completion(
|
||||
struct usb_transfer_completion_event_data* event)
|
||||
{
|
||||
int i;
|
||||
switch(event->endpoint) {
|
||||
case EP_CONTROL:
|
||||
logf("ctrl handled %ld",current_tick);
|
||||
usb_core_control_request_handler((struct usb_ctrlrequest*)event->data);
|
||||
usb_core_control_request_handler(
|
||||
(struct usb_ctrlrequest*)event->data);
|
||||
break;
|
||||
#ifdef USB_STORAGE
|
||||
case EP_MASS_STORAGE:
|
||||
usb_storage_transfer_complete(event->in,event->status,event->length);
|
||||
default:
|
||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||
if(drivers[i].enabled &&
|
||||
drivers[i].usb_endpoint == event->endpoint &&
|
||||
drivers[i].transfer_complete != NULL)
|
||||
{
|
||||
drivers[i].transfer_complete(event->in,
|
||||
event->status,event->length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef USB_SERIAL
|
||||
case EP_SERIAL:
|
||||
usb_serial_transfer_complete(event->in,event->status,event->length);
|
||||
break;
|
||||
#endif
|
||||
#ifdef USB_CHARGING_ONLY
|
||||
case EP_CHARGING_ONLY:
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void usb_core_enable_protocol(int driver,bool enabled)
|
||||
void usb_core_enable_driver(int driver,bool enabled)
|
||||
{
|
||||
switch(driver) {
|
||||
#ifdef USB_STORAGE
|
||||
case USB_DRIVER_MASS_STORAGE:
|
||||
usb_core_storage_enabled = enabled;
|
||||
break;
|
||||
#endif
|
||||
#ifdef USB_SERIAL
|
||||
case USB_DRIVER_SERIAL:
|
||||
usb_core_serial_enabled = enabled;
|
||||
break;
|
||||
#endif
|
||||
#ifdef USB_CHARGING_ONLY
|
||||
case USB_DRIVER_CHARGING_ONLY:
|
||||
usb_core_charging_enabled = enabled;
|
||||
break;
|
||||
#endif
|
||||
drivers[driver].enabled = enabled;
|
||||
}
|
||||
|
||||
bool usb_core_driver_enabled(int driver)
|
||||
{
|
||||
return drivers[driver].enabled;
|
||||
}
|
||||
|
||||
static void usb_core_set_serial_function_id(void)
|
||||
{
|
||||
int id = 0;
|
||||
int i;
|
||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||
if(drivers[i].enabled)
|
||||
id |= 1<<i;
|
||||
}
|
||||
usb_string_iSerial.wString[0] = hex[id];
|
||||
}
|
||||
|
||||
static void allocate_interfaces_and_endpoints(void)
|
||||
{
|
||||
int i;
|
||||
int interface=0;
|
||||
int endpoint=1;
|
||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||
if(drivers[i].enabled) {
|
||||
drivers[i].usb_endpoint = endpoint++;
|
||||
drivers[i].usb_interface = interface++;
|
||||
}
|
||||
if(endpoint>NUM_ENDPOINTS) {
|
||||
drivers[i].enabled = false;
|
||||
}
|
||||
}
|
||||
usb_core_num_interfaces = interface;
|
||||
}
|
||||
|
||||
static void usb_core_control_request_handler(struct usb_ctrlrequest* req)
|
||||
{
|
||||
int i;
|
||||
if(usb_state == DEFAULT) {
|
||||
set_serial_descriptor();
|
||||
|
||||
int serial_function_id = 0;
|
||||
#ifdef USB_STORAGE
|
||||
if(usb_core_storage_enabled) {
|
||||
usb_request_exclusive_ata();
|
||||
serial_function_id |= 1;
|
||||
usb_core_set_serial_function_id();
|
||||
|
||||
allocate_interfaces_and_endpoints();
|
||||
|
||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||
if(drivers[i].enabled &&
|
||||
drivers[i].needs_exclusive_ata) {
|
||||
usb_request_exclusive_ata();
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USB_SERIAL
|
||||
if(usb_core_serial_enabled)
|
||||
serial_function_id |= 2;
|
||||
#endif
|
||||
usb_string_iSerial.wString[0] = hex[serial_function_id];
|
||||
}
|
||||
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_SET_CONFIGURATION:
|
||||
logf("usb_core: SET_CONFIG");
|
||||
usb_drv_cancel_all_transfers();
|
||||
if (req->wValue){
|
||||
usb_state = CONFIGURED;
|
||||
#ifdef USB_STORAGE
|
||||
if(usb_core_storage_enabled)
|
||||
usb_storage_control_request(req);
|
||||
#endif
|
||||
switch(req->bRequestType & 0x1f) {
|
||||
case 0: /* Device */
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_GET_CONFIGURATION: {
|
||||
logf("usb_core: GET_CONFIG");
|
||||
if (usb_state == ADDRESS)
|
||||
response_data[0] = 0;
|
||||
else
|
||||
response_data[0] = 1;
|
||||
if(usb_drv_send(EP_CONTROL, response_data, 1)!= 0)
|
||||
break;
|
||||
ack_control(req);
|
||||
break;
|
||||
case USB_REQ_SET_CONFIGURATION:
|
||||
logf("usb_core: SET_CONFIG");
|
||||
usb_drv_cancel_all_transfers();
|
||||
if (req->wValue) {
|
||||
usb_state = CONFIGURED;
|
||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||
if(drivers[i].enabled &&
|
||||
drivers[i].init_connection!=NULL)
|
||||
{
|
||||
drivers[i].init_connection(
|
||||
drivers[i].usb_interface,
|
||||
drivers[i].usb_endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
usb_state = ADDRESS;
|
||||
}
|
||||
ack_control(req);
|
||||
break;
|
||||
}
|
||||
case USB_REQ_SET_ADDRESS: {
|
||||
unsigned char address = req->wValue;
|
||||
logf("usb_core: SET_ADR %d", address);
|
||||
if(ack_control(req)!=0)
|
||||
break;
|
||||
usb_drv_cancel_all_transfers();
|
||||
usb_address = address;
|
||||
usb_drv_set_address(usb_address);
|
||||
usb_state = ADDRESS;
|
||||
break;
|
||||
}
|
||||
case USB_REQ_GET_DESCRIPTOR: {
|
||||
int index = req->wValue & 0xff;
|
||||
int length = req->wLength;
|
||||
int size;
|
||||
const void* ptr = NULL;
|
||||
logf("usb_core: GET_DESC %d", req->wValue >> 8);
|
||||
|
||||
#ifdef USB_SERIAL
|
||||
if(usb_core_serial_enabled)
|
||||
usb_serial_control_request(req);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
usb_state = ADDRESS;
|
||||
}
|
||||
ack_control(req);
|
||||
break;
|
||||
switch (req->wValue >> 8) { /* type */
|
||||
case USB_DT_DEVICE:
|
||||
ptr = &device_descriptor;
|
||||
size = sizeof(struct usb_device_descriptor);
|
||||
break;
|
||||
|
||||
case USB_REQ_GET_CONFIGURATION: {
|
||||
logf("usb_core: GET_CONFIG");
|
||||
if (usb_state == ADDRESS)
|
||||
response_data[0] = 0;
|
||||
else
|
||||
response_data[0] = 1;
|
||||
if(usb_drv_send(EP_CONTROL, response_data, 1)!= 0)
|
||||
break;
|
||||
ack_control(req);
|
||||
break;
|
||||
}
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
case USB_DT_CONFIG: {
|
||||
int max_packet_size;
|
||||
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
logf("usb_core: SET_INTERFACE");
|
||||
ack_control(req);
|
||||
break;
|
||||
if(req->wValue >> 8 == USB_DT_CONFIG) {
|
||||
if(usb_drv_port_speed())
|
||||
max_packet_size=512;
|
||||
else
|
||||
max_packet_size=64;
|
||||
config_descriptor.bDescriptorType=USB_DT_CONFIG;
|
||||
}
|
||||
else {
|
||||
if(usb_drv_port_speed())
|
||||
max_packet_size=64;
|
||||
else
|
||||
max_packet_size=512;
|
||||
config_descriptor.bDescriptorType =
|
||||
USB_DT_OTHER_SPEED_CONFIG;
|
||||
}
|
||||
size = sizeof(struct usb_config_descriptor);
|
||||
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
logf("usb_core: GET_INTERFACE");
|
||||
response_data[0] = 0;
|
||||
if(usb_drv_send(EP_CONTROL, response_data, 1)!=0)
|
||||
break;
|
||||
ack_control(req);
|
||||
break;
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
logf("usb_core: CLEAR_FEATURE");
|
||||
if (req->wValue)
|
||||
usb_drv_stall(req->wIndex & 0xf, false,(req->wIndex & 0x80) !=0);
|
||||
else
|
||||
usb_drv_stall(req->wIndex & 0xf, false,(req->wIndex & 0x80) !=0);
|
||||
ack_control(req);
|
||||
break;
|
||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||
if(drivers[i].enabled &&
|
||||
drivers[i].get_config_descriptor)
|
||||
{
|
||||
size+=drivers[i].get_config_descriptor(
|
||||
&response_data[size],
|
||||
max_packet_size,
|
||||
drivers[i].usb_interface,
|
||||
drivers[i].usb_endpoint);
|
||||
}
|
||||
}
|
||||
config_descriptor.bNumInterfaces =
|
||||
usb_core_num_interfaces;
|
||||
config_descriptor.wTotalLength = size;
|
||||
memcpy(&response_data[0],&config_descriptor,
|
||||
sizeof(struct usb_config_descriptor));
|
||||
|
||||
case USB_REQ_SET_FEATURE:
|
||||
logf("usb_core: SET_FEATURE");
|
||||
switch(req->bRequestType & 0x0f){
|
||||
case 0: /* Device */
|
||||
ptr = response_data;
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_DT_STRING:
|
||||
logf("STRING %d",index);
|
||||
if ((unsigned)index < (sizeof(usb_strings)/
|
||||
sizeof(struct usb_string_descriptor*)))
|
||||
{
|
||||
size = usb_strings[index]->bLength;
|
||||
memcpy(&response_data[0],usb_strings[index],
|
||||
size);
|
||||
ptr = response_data;
|
||||
}
|
||||
else {
|
||||
logf("bad string id %d", index);
|
||||
usb_drv_stall(EP_CONTROL, true,true);
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DT_DEVICE_QUALIFIER:
|
||||
ptr = &qualifier_descriptor;
|
||||
size = sizeof (struct usb_qualifier_descriptor);
|
||||
break;
|
||||
|
||||
default:
|
||||
logf("bad desc %d", req->wValue >> 8);
|
||||
usb_drv_stall(EP_CONTROL, true,true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
unsigned char *uncached = (void*)UNCACHED_ADDR(ptr);
|
||||
length = MIN(size, length);
|
||||
if(usb_drv_send(EP_CONTROL, uncached, length)!=0)
|
||||
break;
|
||||
}
|
||||
ack_control(req);
|
||||
break;
|
||||
} /* USB_REQ_GET_DESCRIPTOR */
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
break;
|
||||
case USB_REQ_SET_FEATURE:
|
||||
if(req->wValue == 2) { /* TEST_MODE */
|
||||
int mode=req->wIndex>>8;
|
||||
ack_control(req);
|
||||
usb_drv_set_test_mode(mode);
|
||||
}
|
||||
break;
|
||||
case 2: /* Endpoint */
|
||||
if (req->wValue)
|
||||
usb_drv_stall(req->wIndex & 0xf, true,(req->wIndex & 0x80) !=0);
|
||||
else
|
||||
usb_drv_stall(req->wIndex & 0xf, false,(req->wIndex & 0x80) !=0);
|
||||
case USB_REQ_GET_STATUS:
|
||||
response_data[0]= 0;
|
||||
response_data[1]= 0;
|
||||
if(usb_drv_send(EP_CONTROL, response_data, 2)!=0)
|
||||
break;
|
||||
ack_control(req);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_REQ_SET_ADDRESS: {
|
||||
unsigned char address = req->wValue;
|
||||
logf("usb_core: SET_ADR %d", address);
|
||||
if(ack_control(req)!=0)
|
||||
break;
|
||||
usb_drv_cancel_all_transfers();
|
||||
usb_address = address;
|
||||
usb_drv_set_address(usb_address);
|
||||
usb_state = ADDRESS;
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_REQ_GET_STATUS: {
|
||||
response_data[0]= 0;
|
||||
response_data[1]= 0;
|
||||
logf("usb_core: GET_STATUS");
|
||||
if(req->wIndex>0) {
|
||||
if(usb_drv_stalled(req->wIndex&0xf,(req->wIndex&0x80)!=0))
|
||||
response_data[0] = 1;
|
||||
}
|
||||
logf("usb_core: %X %X",response_data[0],response_data[1]);
|
||||
if(usb_drv_send(EP_CONTROL, response_data, 2)!=0)
|
||||
break;
|
||||
ack_control(req);
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_REQ_GET_DESCRIPTOR: {
|
||||
int index = req->wValue & 0xff;
|
||||
int length = req->wLength;
|
||||
int size;
|
||||
const void* ptr = NULL;
|
||||
logf("usb_core: GET_DESC %d", req->wValue >> 8);
|
||||
|
||||
switch (req->wValue >> 8) { /* type */
|
||||
case USB_DT_DEVICE:
|
||||
ptr = &device_descriptor;
|
||||
size = sizeof(struct usb_device_descriptor);
|
||||
case 1: /* Interface */
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
logf("usb_core: SET_INTERFACE");
|
||||
ack_control(req);
|
||||
break;
|
||||
|
||||
case USB_DT_OTHER_SPEED_CONFIG:
|
||||
case USB_DT_CONFIG: {
|
||||
int max_packet_size;
|
||||
int interface_number=0;
|
||||
|
||||
if(req->wValue >> 8 == USB_DT_CONFIG) {
|
||||
if(usb_drv_port_speed()) {
|
||||
max_packet_size=512;
|
||||
}
|
||||
else {
|
||||
max_packet_size=64;
|
||||
}
|
||||
config_descriptor.bDescriptorType=USB_DT_CONFIG;
|
||||
}
|
||||
else {
|
||||
if(usb_drv_port_speed()) {
|
||||
max_packet_size=64;
|
||||
}
|
||||
else {
|
||||
max_packet_size=512;
|
||||
}
|
||||
config_descriptor.bDescriptorType=USB_DT_OTHER_SPEED_CONFIG;
|
||||
}
|
||||
size = sizeof(struct usb_config_descriptor);
|
||||
|
||||
#ifdef USB_STORAGE
|
||||
if(usb_core_storage_enabled){
|
||||
mass_storage_ep_in_descriptor.wMaxPacketSize=max_packet_size;
|
||||
mass_storage_ep_out_descriptor.wMaxPacketSize=max_packet_size;
|
||||
mass_storage_interface_descriptor.bInterfaceNumber=interface_number;
|
||||
interface_number++;
|
||||
|
||||
memcpy(&response_data[size],&mass_storage_interface_descriptor,sizeof(struct usb_interface_descriptor));
|
||||
size += sizeof(struct usb_interface_descriptor);
|
||||
memcpy(&response_data[size],&mass_storage_ep_in_descriptor,sizeof(struct usb_endpoint_descriptor));
|
||||
size += sizeof(struct usb_endpoint_descriptor);
|
||||
memcpy(&response_data[size],&mass_storage_ep_out_descriptor,sizeof(struct usb_endpoint_descriptor));
|
||||
size += sizeof(struct usb_endpoint_descriptor);
|
||||
}
|
||||
#endif
|
||||
#ifdef USB_SERIAL
|
||||
if(usb_core_serial_enabled){
|
||||
serial_ep_in_descriptor.wMaxPacketSize=max_packet_size;
|
||||
serial_ep_out_descriptor.wMaxPacketSize=max_packet_size;
|
||||
serial_interface_descriptor.bInterfaceNumber=interface_number;
|
||||
interface_number++;
|
||||
|
||||
memcpy(&response_data[size],&serial_interface_descriptor,sizeof(struct usb_interface_descriptor));
|
||||
size += sizeof(struct usb_interface_descriptor);
|
||||
memcpy(&response_data[size],&serial_ep_in_descriptor,sizeof(struct usb_endpoint_descriptor));
|
||||
size += sizeof(struct usb_endpoint_descriptor);
|
||||
memcpy(&response_data[size],&serial_ep_out_descriptor,sizeof(struct usb_endpoint_descriptor));
|
||||
size += sizeof(struct usb_endpoint_descriptor);
|
||||
}
|
||||
#endif
|
||||
#ifdef USB_CHARGING_ONLY
|
||||
if(usb_core_charging_enabled && interface_number == 0){
|
||||
charging_interface_descriptor.bInterfaceNumber=interface_number;
|
||||
interface_number++;
|
||||
memcpy(&response_data[size],&charging_interface_descriptor,sizeof(struct usb_interface_descriptor));
|
||||
size += sizeof(struct usb_interface_descriptor);
|
||||
}
|
||||
#endif
|
||||
config_descriptor.bNumInterfaces=interface_number;
|
||||
config_descriptor.wTotalLength = size;
|
||||
memcpy(&response_data[0],&config_descriptor,sizeof(struct usb_config_descriptor));
|
||||
|
||||
ptr = response_data;
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
logf("usb_core: GET_INTERFACE");
|
||||
response_data[0] = 0;
|
||||
if(usb_drv_send(EP_CONTROL, response_data, 1)!=0)
|
||||
break;
|
||||
ack_control(req);
|
||||
break;
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
break;
|
||||
case USB_REQ_SET_FEATURE:
|
||||
break;
|
||||
case USB_REQ_GET_STATUS:
|
||||
response_data[0]= 0;
|
||||
response_data[1]= 0;
|
||||
if(usb_drv_send(EP_CONTROL, response_data, 2)!=0)
|
||||
break;
|
||||
ack_control(req);
|
||||
break;
|
||||
default: {
|
||||
bool handled=false;
|
||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||
if(drivers[i].enabled &&
|
||||
drivers[i].control_request &&
|
||||
drivers[i].usb_interface == (req->wIndex))
|
||||
{
|
||||
handled = drivers[i].control_request(req);
|
||||
}
|
||||
}
|
||||
|
||||
case USB_DT_STRING:
|
||||
logf("STRING %d",index);
|
||||
if ((unsigned)index < (sizeof(usb_strings)/sizeof(struct usb_string_descriptor*))) {
|
||||
size = usb_strings[index]->bLength;
|
||||
memcpy(&response_data[0],usb_strings[index],size);
|
||||
ptr = response_data;
|
||||
}
|
||||
else {
|
||||
logf("bad string id %d", index);
|
||||
if(!handled) {
|
||||
/* nope. flag error */
|
||||
logf("usb bad req %d", req->bRequest);
|
||||
usb_drv_stall(EP_CONTROL, true,true);
|
||||
ack_control(req);
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DT_DEVICE_QUALIFIER:
|
||||
ptr = &qualifier_descriptor;
|
||||
size = sizeof (struct usb_qualifier_descriptor);
|
||||
break;
|
||||
|
||||
default:
|
||||
logf("bad desc %d", req->wValue >> 8);
|
||||
usb_drv_stall(EP_CONTROL, true,true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
length = MIN(size, length);
|
||||
if(usb_drv_send(EP_CONTROL, (void*)UNCACHED_ADDR(ptr), length)!=0)
|
||||
break;
|
||||
}
|
||||
ack_control(req);
|
||||
break;
|
||||
} /* USB_REQ_GET_DESCRIPTOR */
|
||||
|
||||
default: {
|
||||
bool handled=false;
|
||||
if((req->bRequestType & 0x1f) == 1) /* Interface */
|
||||
{
|
||||
#ifdef USB_STORAGE
|
||||
/* does usb_storage know this request? */
|
||||
if(req->wIndex == mass_storage_interface_descriptor.bInterfaceNumber)
|
||||
{
|
||||
handled = usb_storage_control_request(req);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USB_SERIAL
|
||||
/* does usb_serial know this request? */
|
||||
if(req->wIndex == serial_interface_descriptor.bInterfaceNumber)
|
||||
{
|
||||
handled = usb_serial_control_request(req);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
if(!handled)
|
||||
{
|
||||
/* nope. flag error */
|
||||
logf("usb bad req %d", req->bRequest);
|
||||
usb_drv_stall(EP_CONTROL, true,true);
|
||||
ack_control(req);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: /* Endpoint */
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
if (req->wValue == 0 ) /* ENDPOINT_HALT */
|
||||
usb_drv_stall(req->wIndex & 0xf, false,
|
||||
(req->wIndex & 0x80) !=0);
|
||||
ack_control(req);
|
||||
break;
|
||||
case USB_REQ_SET_FEATURE:
|
||||
if (req->wValue == 0 ) /* ENDPOINT_HALT */
|
||||
usb_drv_stall(req->wIndex & 0xf, true,
|
||||
(req->wIndex & 0x80) !=0);
|
||||
ack_control(req);
|
||||
break;
|
||||
case USB_REQ_GET_STATUS:
|
||||
response_data[0]= 0;
|
||||
response_data[1]= 0;
|
||||
logf("usb_core: GET_STATUS");
|
||||
if(req->wIndex>0)
|
||||
response_data[0] = usb_drv_stalled(req->wIndex&0xf,
|
||||
(req->wIndex&0x80)!=0);
|
||||
if(usb_drv_send(EP_CONTROL, response_data, 2)!=0)
|
||||
break;
|
||||
ack_control(req);
|
||||
break;
|
||||
default: {
|
||||
bool handled=false;
|
||||
for(i=0;i<USB_NUM_DRIVERS;i++) {
|
||||
if(drivers[i].enabled &&
|
||||
drivers[i].control_request &&
|
||||
drivers[i].usb_endpoint == (req->wIndex & 0xf))
|
||||
{
|
||||
handled = drivers[i].control_request(req);
|
||||
}
|
||||
}
|
||||
if(!handled) {
|
||||
/* nope. flag error */
|
||||
logf("usb bad req %d", req->bRequest);
|
||||
usb_drv_stall(EP_CONTROL, true,true);
|
||||
ack_control(req);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
logf("control handled");
|
||||
}
|
||||
|
@ -691,10 +691,6 @@ void usb_core_bus_reset(void)
|
|||
/* called by usb_drv_transfer_completed() */
|
||||
void usb_core_transfer_complete(int endpoint, bool in, int status,int length)
|
||||
{
|
||||
#if defined(USB_CHARGING_ONLY) || defined(USB_STORAGE)
|
||||
(void)in;
|
||||
#endif
|
||||
|
||||
switch (endpoint) {
|
||||
case EP_CONTROL:
|
||||
/* already handled */
|
||||
|
|
|
@ -27,6 +27,31 @@
|
|||
|
||||
#ifdef USB_SERIAL
|
||||
|
||||
/* serial interface */
|
||||
struct usb_interface_descriptor __attribute__((aligned(2)))
|
||||
interface_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = 0
|
||||
};
|
||||
|
||||
struct usb_endpoint_descriptor __attribute__((aligned(2))) endpoint_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 0,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 0,
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
#define BUFFER_SIZE 512 /* Max 16k because of controller limitations */
|
||||
static unsigned char _send_buffer[BUFFER_SIZE] __attribute__((aligned(32)));
|
||||
static unsigned char* send_buffer;
|
||||
|
@ -38,8 +63,66 @@ static int buffer_start;
|
|||
static int buffer_length;
|
||||
static bool active = false;
|
||||
|
||||
static int usb_endpoint;
|
||||
static int usb_interface;
|
||||
|
||||
static struct mutex sendlock;
|
||||
|
||||
static void sendout(void)
|
||||
{
|
||||
if(buffer_start+buffer_length > BUFFER_SIZE)
|
||||
{
|
||||
/* Buffer wraps. Only send the first part */
|
||||
usb_drv_send_nonblocking(usb_endpoint, &send_buffer[buffer_start],
|
||||
(BUFFER_SIZE - buffer_start));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Send everything */
|
||||
usb_drv_send_nonblocking(usb_endpoint, &send_buffer[buffer_start],
|
||||
buffer_length);
|
||||
}
|
||||
busy_sending=true;
|
||||
}
|
||||
|
||||
int usb_serial_get_config_descriptor(unsigned char *dest,int max_packet_size,
|
||||
int interface_number,int endpoint)
|
||||
{
|
||||
endpoint_descriptor.wMaxPacketSize=max_packet_size;
|
||||
interface_descriptor.bInterfaceNumber=interface_number;
|
||||
|
||||
|
||||
memcpy(dest,&interface_descriptor,sizeof(struct usb_interface_descriptor));
|
||||
dest+=sizeof(struct usb_interface_descriptor);
|
||||
|
||||
endpoint_descriptor.bEndpointAddress = endpoint | USB_DIR_IN,
|
||||
memcpy(dest,&endpoint_descriptor,sizeof(struct usb_endpoint_descriptor));
|
||||
dest+=sizeof(struct usb_endpoint_descriptor);
|
||||
|
||||
endpoint_descriptor.bEndpointAddress = endpoint | USB_DIR_OUT,
|
||||
memcpy(dest,&endpoint_descriptor,sizeof(struct usb_endpoint_descriptor));
|
||||
return sizeof(struct usb_interface_descriptor) +
|
||||
2 * sizeof(struct usb_endpoint_descriptor);
|
||||
}
|
||||
|
||||
void usb_serial_init_connection(int interface,int endpoint)
|
||||
{
|
||||
usb_interface = interface;
|
||||
usb_endpoint = endpoint;
|
||||
|
||||
/* prime rx endpoint */
|
||||
usb_drv_recv(usb_endpoint, receive_buffer, sizeof _receive_buffer);
|
||||
|
||||
/* we come here too after a bus reset, so reset some data */
|
||||
mutex_lock(&sendlock);
|
||||
busy_sending = false;
|
||||
if(buffer_length>0)
|
||||
{
|
||||
sendout();
|
||||
}
|
||||
mutex_unlock(&sendlock);
|
||||
}
|
||||
|
||||
/* called by usb_code_init() */
|
||||
void usb_serial_init(void)
|
||||
{
|
||||
|
@ -53,26 +136,11 @@ void usb_serial_init(void)
|
|||
mutex_init(&sendlock);
|
||||
}
|
||||
|
||||
void usb_serial_exit(void)
|
||||
void usb_serial_disconnect(void)
|
||||
{
|
||||
active = false;
|
||||
}
|
||||
|
||||
static void sendout(void)
|
||||
{
|
||||
if(buffer_start+buffer_length > BUFFER_SIZE)
|
||||
{
|
||||
/* Buffer wraps. Only send the first part */
|
||||
usb_drv_send_nonblocking(EP_SERIAL, &send_buffer[buffer_start],(BUFFER_SIZE - buffer_start));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Send everything */
|
||||
usb_drv_send_nonblocking(EP_SERIAL, &send_buffer[buffer_start],buffer_length);
|
||||
}
|
||||
busy_sending=true;
|
||||
}
|
||||
|
||||
void usb_serial_send(unsigned char *data,int length)
|
||||
{
|
||||
if(!active)
|
||||
|
@ -85,13 +153,14 @@ void usb_serial_send(unsigned char *data,int length)
|
|||
/* current buffer wraps, so new data can't */
|
||||
int available_space = BUFFER_SIZE - buffer_length;
|
||||
length=MIN(length,available_space);
|
||||
memcpy(&send_buffer[(buffer_start+buffer_length)%BUFFER_SIZE],data,length);
|
||||
memcpy(&send_buffer[(buffer_start+buffer_length)%BUFFER_SIZE],
|
||||
data,length);
|
||||
buffer_length+=length;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* current buffer doesn't wrap, so new data might */
|
||||
int available_end_space = (BUFFER_SIZE - (buffer_start + buffer_length));
|
||||
int available_end_space = (BUFFER_SIZE - (buffer_start+buffer_length));
|
||||
int first_chunk = MIN(length,available_end_space);
|
||||
memcpy(&send_buffer[buffer_start + buffer_length],data,first_chunk);
|
||||
length-=first_chunk;
|
||||
|
@ -121,7 +190,7 @@ void usb_serial_transfer_complete(bool in, int status, int length)
|
|||
case false:
|
||||
logf("serial: %s", receive_buffer);
|
||||
/* Data received. TODO : Do something with it ? */
|
||||
usb_drv_recv(EP_SERIAL, receive_buffer, sizeof _receive_buffer);
|
||||
usb_drv_recv(usb_endpoint, receive_buffer, sizeof _receive_buffer);
|
||||
break;
|
||||
|
||||
case true:
|
||||
|
@ -148,26 +217,9 @@ bool usb_serial_control_request(struct usb_ctrlrequest* req)
|
|||
{
|
||||
bool handled = false;
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_SET_CONFIGURATION:
|
||||
logf("serial: set config");
|
||||
/* prime rx endpoint */
|
||||
usb_drv_recv(EP_SERIAL, receive_buffer, sizeof _receive_buffer);
|
||||
handled = true;
|
||||
|
||||
/* we come here too after a bus reset, so reset some data */
|
||||
mutex_lock(&sendlock);
|
||||
busy_sending = false;
|
||||
if(buffer_length>0)
|
||||
{
|
||||
sendout();
|
||||
}
|
||||
mutex_unlock(&sendlock);
|
||||
break;
|
||||
|
||||
default:
|
||||
logf("serial: unhandeld req %d", req->bRequest);
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,11 @@
|
|||
|
||||
#include "usb_ch9.h"
|
||||
|
||||
int usb_serial_get_config_descriptor(unsigned char *dest,int max_packet_size,
|
||||
int interface_number, int endpoint);
|
||||
void usb_serial_init_connection(int interface,int endpoint);
|
||||
void usb_serial_init(void);
|
||||
void usb_serial_exit(void);
|
||||
void usb_serial_disconnect(void);
|
||||
void usb_serial_transfer_complete(bool in, int status, int length);
|
||||
bool usb_serial_control_request(struct usb_ctrlrequest* req);
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
/* Needed to get at the audio buffer */
|
||||
#include "audio.h"
|
||||
|
||||
|
||||
#ifdef USB_STORAGE
|
||||
|
||||
/* Enable the following define to export only the SD card slot. This
|
||||
|
@ -85,6 +86,35 @@
|
|||
|
||||
#define SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA 0x02000000
|
||||
|
||||
/* storage interface */
|
||||
|
||||
#define USB_SC_SCSI 0x06 /* Transparent */
|
||||
#define USB_PROT_BULK 0x50 /* bulk only */
|
||||
|
||||
static struct usb_interface_descriptor __attribute__((aligned(2)))
|
||||
interface_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
|
||||
.bInterfaceSubClass = USB_SC_SCSI,
|
||||
.bInterfaceProtocol = USB_PROT_BULK,
|
||||
.iInterface = 0
|
||||
};
|
||||
|
||||
static struct usb_endpoint_descriptor __attribute__((aligned(2)))
|
||||
endpoint_descriptor =
|
||||
{
|
||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 0,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||
.wMaxPacketSize = 0,
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
struct inquiry_data {
|
||||
unsigned char DeviceType;
|
||||
|
@ -111,7 +141,7 @@ struct report_lun_data {
|
|||
struct sense_data {
|
||||
unsigned char ResponseCode;
|
||||
unsigned char Obsolete;
|
||||
unsigned char filemark_eom_ili_sensekey;
|
||||
unsigned char fei_sensekey;
|
||||
unsigned int Information;
|
||||
unsigned char AdditionalSenseLength;
|
||||
unsigned int CommandSpecificInformation;
|
||||
|
@ -122,15 +152,15 @@ struct sense_data {
|
|||
unsigned short SenseKeySpecific;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mode_sense_block_descriptor_longlba {
|
||||
unsigned char number_of_blocks[8];
|
||||
struct mode_sense_bdesc_longlba {
|
||||
unsigned char num_blocks[8];
|
||||
unsigned char reserved[4];
|
||||
unsigned char block_size[4];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mode_sense_block_descriptor_shortlba {
|
||||
struct mode_sense_bdesc_shortlba {
|
||||
unsigned char density_code;
|
||||
unsigned char number_of_blocks[3];
|
||||
unsigned char num_blocks[3];
|
||||
unsigned char reserved;
|
||||
unsigned char block_size[3];
|
||||
} __attribute__ ((packed));
|
||||
|
@ -142,7 +172,7 @@ struct mode_sense_data_10 {
|
|||
unsigned char longlba;
|
||||
unsigned char reserved;
|
||||
unsigned short block_descriptor_length;
|
||||
struct mode_sense_block_descriptor_longlba block_descriptor;
|
||||
struct mode_sense_bdesc_longlba block_descriptor;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct mode_sense_data_6 {
|
||||
|
@ -150,7 +180,7 @@ struct mode_sense_data_6 {
|
|||
unsigned char medium_type;
|
||||
unsigned char device_specific;
|
||||
unsigned char block_descriptor_length;
|
||||
struct mode_sense_block_descriptor_shortlba block_descriptor;
|
||||
struct mode_sense_bdesc_shortlba block_descriptor;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct command_block_wrapper {
|
||||
|
@ -188,8 +218,8 @@ static union {
|
|||
struct capacity* capacity_data;
|
||||
struct format_capacity* format_capacity_data;
|
||||
struct sense_data *sense_data;
|
||||
struct mode_sense_data_6 *mode_sense_data_6;
|
||||
struct mode_sense_data_10 *mode_sense_data_10;
|
||||
struct mode_sense_data_6 *ms_data_6;
|
||||
struct mode_sense_data_10 *ms_data_10;
|
||||
struct report_lun_data *lun_data;
|
||||
struct command_status_wrapper* csw;
|
||||
char *max_lun;
|
||||
|
@ -203,7 +233,7 @@ static struct {
|
|||
unsigned char *data[2];
|
||||
unsigned char data_select;
|
||||
unsigned int last_result;
|
||||
} current_cmd;
|
||||
} cur_cmd;
|
||||
|
||||
static struct {
|
||||
unsigned char sense_key;
|
||||
|
@ -221,6 +251,9 @@ static void identify2inquiry(int lun);
|
|||
static void send_and_read_next(void);
|
||||
static bool ejected[NUM_VOLUMES];
|
||||
|
||||
static int usb_endpoint;
|
||||
static int usb_interface;
|
||||
|
||||
static enum {
|
||||
WAITING_FOR_COMMAND,
|
||||
SENDING_BLOCKS,
|
||||
|
@ -238,6 +271,49 @@ void usb_storage_init(void)
|
|||
logf("usb_storage_init done");
|
||||
}
|
||||
|
||||
int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size,
|
||||
int interface_number,int endpoint)
|
||||
{
|
||||
endpoint_descriptor.wMaxPacketSize=max_packet_size;
|
||||
interface_descriptor.bInterfaceNumber=interface_number;
|
||||
|
||||
|
||||
memcpy(dest,&interface_descriptor,
|
||||
sizeof(struct usb_interface_descriptor));
|
||||
dest+=sizeof(struct usb_interface_descriptor);
|
||||
|
||||
endpoint_descriptor.bEndpointAddress = endpoint | USB_DIR_IN,
|
||||
memcpy(dest,&endpoint_descriptor,
|
||||
sizeof(struct usb_endpoint_descriptor));
|
||||
dest+=sizeof(struct usb_endpoint_descriptor);
|
||||
|
||||
endpoint_descriptor.bEndpointAddress = endpoint | USB_DIR_OUT,
|
||||
memcpy(dest,&endpoint_descriptor,
|
||||
sizeof(struct usb_endpoint_descriptor));
|
||||
|
||||
return sizeof(struct usb_interface_descriptor) +
|
||||
2*sizeof(struct usb_endpoint_descriptor);
|
||||
}
|
||||
|
||||
void usb_storage_init_connection(int interface,int endpoint)
|
||||
{
|
||||
size_t bufsize;
|
||||
unsigned char * audio_buffer;
|
||||
|
||||
usb_interface = interface;
|
||||
usb_endpoint = endpoint;
|
||||
|
||||
logf("ums: set config");
|
||||
/* prime rx endpoint. We only need room for commands */
|
||||
state = WAITING_FOR_COMMAND;
|
||||
|
||||
/* TODO : check if bufsize is at least 32K ? */
|
||||
audio_buffer = audio_get_buffer(false,&bufsize);
|
||||
tb.transfer_buffer =
|
||||
(void *)UNCACHED_ADDR((unsigned int)(audio_buffer + 31) & 0xffffffe0);
|
||||
usb_drv_recv(usb_endpoint, tb.transfer_buffer, 1024);
|
||||
}
|
||||
|
||||
/* called by usb_core_transfer_complete() */
|
||||
void usb_storage_transfer_complete(bool in,int status,int length)
|
||||
{
|
||||
|
@ -249,26 +325,31 @@ void usb_storage_transfer_complete(bool in,int status,int length)
|
|||
if(in==true) {
|
||||
logf("IN received in RECEIVING");
|
||||
}
|
||||
logf("scsi write %d %d", current_cmd.sector, current_cmd.count);
|
||||
logf("scsi write %d %d", cur_cmd.sector, cur_cmd.count);
|
||||
if(status==0) {
|
||||
if((unsigned int)length!=(SECTOR_SIZE*current_cmd.count)
|
||||
if((unsigned int)length!=(SECTOR_SIZE*cur_cmd.count)
|
||||
&& (unsigned int)length!=BUFFER_SIZE) {
|
||||
logf("unexpected length :%d",length);
|
||||
}
|
||||
|
||||
unsigned int next_sector = current_cmd.sector + (BUFFER_SIZE/SECTOR_SIZE);
|
||||
unsigned int next_count = current_cmd.count - MIN(current_cmd.count,BUFFER_SIZE/SECTOR_SIZE);
|
||||
unsigned int next_sector = cur_cmd.sector +
|
||||
(BUFFER_SIZE/SECTOR_SIZE);
|
||||
unsigned int next_count = cur_cmd.count -
|
||||
MIN(cur_cmd.count,BUFFER_SIZE/SECTOR_SIZE);
|
||||
|
||||
if(next_count!=0) {
|
||||
/* Ask the host to send more, to the other buffer */
|
||||
receive_block_data(current_cmd.data[!current_cmd.data_select],
|
||||
receive_block_data(cur_cmd.data[!cur_cmd.data_select],
|
||||
MIN(BUFFER_SIZE,next_count*SECTOR_SIZE));
|
||||
}
|
||||
|
||||
/* Now write the data that just came in, while the host is sending the next bit */
|
||||
int result = ata_write_sectors(IF_MV2(current_cmd.lun,)
|
||||
current_cmd.sector, MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count),
|
||||
current_cmd.data[current_cmd.data_select]);
|
||||
/* Now write the data that just came in, while the host is
|
||||
sending the next bit */
|
||||
int result = ata_write_sectors(IF_MV2(cur_cmd.lun,)
|
||||
cur_cmd.sector,
|
||||
MIN(BUFFER_SIZE/SECTOR_SIZE,
|
||||
cur_cmd.count),
|
||||
cur_cmd.data[cur_cmd.data_select]);
|
||||
if(result != 0) {
|
||||
send_csw(UMS_STATUS_FAIL);
|
||||
cur_sense_data.sense_key=SENSE_MEDIUM_ERROR;
|
||||
|
@ -282,10 +363,10 @@ void usb_storage_transfer_complete(bool in,int status,int length)
|
|||
}
|
||||
|
||||
/* Switch buffers for the next one */
|
||||
current_cmd.data_select=!current_cmd.data_select;
|
||||
cur_cmd.data_select=!cur_cmd.data_select;
|
||||
|
||||
current_cmd.sector = next_sector;
|
||||
current_cmd.count = next_count;
|
||||
cur_cmd.sector = next_sector;
|
||||
cur_cmd.count = next_count;
|
||||
|
||||
}
|
||||
else {
|
||||
|
@ -307,8 +388,8 @@ void usb_storage_transfer_complete(bool in,int status,int length)
|
|||
handle_scsi(cbw);
|
||||
}
|
||||
else {
|
||||
usb_drv_stall(EP_MASS_STORAGE, true,true);
|
||||
usb_drv_stall(EP_MASS_STORAGE, true,false);
|
||||
usb_drv_stall(usb_endpoint, true,true);
|
||||
usb_drv_stall(usb_endpoint, true,false);
|
||||
}
|
||||
break;
|
||||
case SENDING_CSW:
|
||||
|
@ -317,7 +398,7 @@ void usb_storage_transfer_complete(bool in,int status,int length)
|
|||
}
|
||||
//logf("csw sent, now go back to idle");
|
||||
state = WAITING_FOR_COMMAND;
|
||||
usb_drv_recv(EP_MASS_STORAGE, tb.transfer_buffer, 1024);
|
||||
usb_drv_recv(usb_endpoint, tb.transfer_buffer, 1024);
|
||||
break;
|
||||
case SENDING_RESULT:
|
||||
if(in==false) {
|
||||
|
@ -342,7 +423,7 @@ void usb_storage_transfer_complete(bool in,int status,int length)
|
|||
logf("OUT received in SENDING");
|
||||
}
|
||||
if(status==0) {
|
||||
if(current_cmd.count==0) {
|
||||
if(cur_cmd.count==0) {
|
||||
//logf("data sent, now send csw");
|
||||
send_csw(UMS_STATUS_GOOD);
|
||||
}
|
||||
|
@ -368,6 +449,7 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req)
|
|||
{
|
||||
bool handled = false;
|
||||
|
||||
|
||||
switch (req->bRequest) {
|
||||
case USB_BULK_GET_MAX_LUN: {
|
||||
#ifdef ONLY_EXPOSE_CARD_SLOT
|
||||
|
@ -386,31 +468,16 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req)
|
|||
logf("ums: bulk reset");
|
||||
state = WAITING_FOR_COMMAND;
|
||||
/* UMS BOT 3.1 says The device shall preserve the value of its bulk
|
||||
* data toggle bits and endpoint STALL conditions despite the Bulk-Only
|
||||
* Mass Storage Reset. */
|
||||
data toggle bits and endpoint STALL conditions despite
|
||||
the Bulk-Only Mass Storage Reset. */
|
||||
#if 0
|
||||
usb_drv_reset_endpoint(EP_MASS_STORAGE, false);
|
||||
usb_drv_reset_endpoint(EP_MASS_STORAGE, true);
|
||||
usb_drv_reset_endpoint(usb_endpoint, false);
|
||||
usb_drv_reset_endpoint(usb_endpoint, true);
|
||||
#endif
|
||||
|
||||
usb_drv_send(EP_CONTROL, NULL, 0); /* ack */
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
case USB_REQ_SET_CONFIGURATION: {
|
||||
size_t bufsize;
|
||||
unsigned char * audio_buffer;
|
||||
logf("ums: set config");
|
||||
/* prime rx endpoint. We only need room for commands */
|
||||
state = WAITING_FOR_COMMAND;
|
||||
|
||||
/* TODO : check if bufsize is at least 32K ? */
|
||||
audio_buffer = audio_get_buffer(false,&bufsize);
|
||||
tb.transfer_buffer = (void *)UNCACHED_ADDR((unsigned int)(audio_buffer + 31) & 0xffffffe0);
|
||||
usb_drv_recv(EP_MASS_STORAGE, tb.transfer_buffer, 1024);
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
|
@ -418,7 +485,7 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req)
|
|||
|
||||
static void send_and_read_next(void)
|
||||
{
|
||||
if(current_cmd.last_result!=0) {
|
||||
if(cur_cmd.last_result!=0) {
|
||||
/* The last read failed. */
|
||||
send_csw(UMS_STATUS_FAIL);
|
||||
cur_sense_data.sense_key=SENSE_MEDIUM_ERROR;
|
||||
|
@ -426,21 +493,23 @@ static void send_and_read_next(void)
|
|||
cur_sense_data.ascq=0;
|
||||
return;
|
||||
}
|
||||
send_block_data(current_cmd.data[current_cmd.data_select],
|
||||
MIN(BUFFER_SIZE,current_cmd.count*SECTOR_SIZE));
|
||||
send_block_data(cur_cmd.data[cur_cmd.data_select],
|
||||
MIN(BUFFER_SIZE,cur_cmd.count*SECTOR_SIZE));
|
||||
|
||||
/* Switch buffers for the next one */
|
||||
current_cmd.data_select=!current_cmd.data_select;
|
||||
cur_cmd.data_select=!cur_cmd.data_select;
|
||||
|
||||
current_cmd.sector+=(BUFFER_SIZE/SECTOR_SIZE);
|
||||
current_cmd.count-=MIN(current_cmd.count,BUFFER_SIZE/SECTOR_SIZE);
|
||||
cur_cmd.sector+=(BUFFER_SIZE/SECTOR_SIZE);
|
||||
cur_cmd.count-=MIN(cur_cmd.count,BUFFER_SIZE/SECTOR_SIZE);
|
||||
|
||||
if(current_cmd.count!=0){
|
||||
if(cur_cmd.count!=0){
|
||||
/* already read the next bit, so we can send it out immediately when the
|
||||
* current transfer completes. */
|
||||
current_cmd.last_result = ata_read_sectors(IF_MV2(current_cmd.lun,) current_cmd.sector,
|
||||
MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count),
|
||||
current_cmd.data[current_cmd.data_select]);
|
||||
cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,)
|
||||
cur_cmd.sector,
|
||||
MIN(BUFFER_SIZE/SECTOR_SIZE,
|
||||
cur_cmd.count),
|
||||
cur_cmd.data[cur_cmd.data_select]);
|
||||
}
|
||||
}
|
||||
/****************************************************************************/
|
||||
|
@ -484,8 +553,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
block_size_mult = disk_sector_multiplier;
|
||||
#endif
|
||||
|
||||
current_cmd.tag = cbw->tag;
|
||||
current_cmd.lun = lun;
|
||||
cur_cmd.tag = cbw->tag;
|
||||
cur_cmd.lun = lun;
|
||||
|
||||
switch (cbw->command_block[0]) {
|
||||
case SCSI_TEST_UNIT_READY:
|
||||
|
@ -524,7 +593,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
#endif
|
||||
tb.lun_data->lun0[1]=0;
|
||||
|
||||
send_command_result(tb.lun_data, MIN(sizeof(struct report_lun_data), length));
|
||||
send_command_result(tb.lun_data,
|
||||
MIN(sizeof(struct report_lun_data), length));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -532,12 +602,13 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
logf("scsi inquiry %d",lun);
|
||||
identify2inquiry(lun);
|
||||
length = MIN(length, cbw->command_block[4]);
|
||||
send_command_result(tb.inquiry, MIN(sizeof(struct inquiry_data), length));
|
||||
send_command_result(tb.inquiry,
|
||||
MIN(sizeof(struct inquiry_data), length));
|
||||
break;
|
||||
|
||||
case SCSI_REQUEST_SENSE: {
|
||||
tb.sense_data->ResponseCode=0x70;/*current error*/
|
||||
tb.sense_data->filemark_eom_ili_sensekey=cur_sense_data.sense_key&0x0f;
|
||||
tb.sense_data->fei_sensekey=cur_sense_data.sense_key&0x0f;
|
||||
tb.sense_data->Information=cur_sense_data.information;
|
||||
tb.sense_data->AdditionalSenseLength=10;
|
||||
tb.sense_data->CommandSpecificInformation=0;
|
||||
|
@ -564,24 +635,36 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
logf("scsi mode_sense_10 %d %X",lun,page_code);
|
||||
switch(page_code) {
|
||||
case 0x3f:
|
||||
tb.mode_sense_data_10->mode_data_length=htobe16(sizeof(struct mode_sense_data_10)-2);
|
||||
tb.mode_sense_data_10->medium_type=0;
|
||||
tb.mode_sense_data_10->device_specific=0;
|
||||
tb.mode_sense_data_10->reserved=0;
|
||||
tb.mode_sense_data_10->longlba=1;
|
||||
tb.mode_sense_data_10->block_descriptor_length=htobe16(sizeof(struct mode_sense_block_descriptor_longlba));
|
||||
memset(tb.mode_sense_data_10->block_descriptor.reserved,0,4);
|
||||
memset(tb.mode_sense_data_10->block_descriptor.number_of_blocks,0,8);
|
||||
tb.mode_sense_data_10->block_descriptor.number_of_blocks[4]=((block_count/block_size_mult) & 0xff000000)>>24;
|
||||
tb.mode_sense_data_10->block_descriptor.number_of_blocks[5]=((block_count/block_size_mult) & 0x00ff0000)>>16;
|
||||
tb.mode_sense_data_10->block_descriptor.number_of_blocks[6]=((block_count/block_size_mult) & 0x0000ff00)>>8;
|
||||
tb.mode_sense_data_10->block_descriptor.number_of_blocks[7]=((block_count/block_size_mult) & 0x000000ff);
|
||||
tb.ms_data_10->mode_data_length =
|
||||
htobe16(sizeof(struct mode_sense_data_10)-2);
|
||||
tb.ms_data_10->medium_type = 0;
|
||||
tb.ms_data_10->device_specific = 0;
|
||||
tb.ms_data_10->reserved = 0;
|
||||
tb.ms_data_10->longlba = 1;
|
||||
tb.ms_data_10->block_descriptor_length =
|
||||
htobe16(sizeof(struct mode_sense_bdesc_longlba));
|
||||
|
||||
tb.mode_sense_data_10->block_descriptor.block_size[0]=((block_size*block_size_mult) & 0xff000000)>>24;
|
||||
tb.mode_sense_data_10->block_descriptor.block_size[1]=((block_size*block_size_mult) & 0x00ff0000)>>16;
|
||||
tb.mode_sense_data_10->block_descriptor.block_size[2]=((block_size*block_size_mult) & 0x0000ff00)>>8;
|
||||
tb.mode_sense_data_10->block_descriptor.block_size[3]=((block_size*block_size_mult) & 0x000000ff);
|
||||
send_command_result(tb.mode_sense_data_10,
|
||||
memset(tb.ms_data_10->block_descriptor.reserved,0,4);
|
||||
memset(tb.ms_data_10->block_descriptor.num_blocks,0,8);
|
||||
|
||||
tb.ms_data_10->block_descriptor.num_blocks[4] =
|
||||
((block_count/block_size_mult) & 0xff000000)>>24;
|
||||
tb.ms_data_10->block_descriptor.num_blocks[5] =
|
||||
((block_count/block_size_mult) & 0x00ff0000)>>16;
|
||||
tb.ms_data_10->block_descriptor.num_blocks[6] =
|
||||
((block_count/block_size_mult) & 0x0000ff00)>>8;
|
||||
tb.ms_data_10->block_descriptor.num_blocks[7] =
|
||||
((block_count/block_size_mult) & 0x000000ff);
|
||||
|
||||
tb.ms_data_10->block_descriptor.block_size[0] =
|
||||
((block_size*block_size_mult) & 0xff000000)>>24;
|
||||
tb.ms_data_10->block_descriptor.block_size[1] =
|
||||
((block_size*block_size_mult) & 0x00ff0000)>>16;
|
||||
tb.ms_data_10->block_descriptor.block_size[2] =
|
||||
((block_size*block_size_mult) & 0x0000ff00)>>8;
|
||||
tb.ms_data_10->block_descriptor.block_size[3] =
|
||||
((block_size*block_size_mult) & 0x000000ff);
|
||||
send_command_result(tb.ms_data_10,
|
||||
MIN(sizeof(struct mode_sense_data_10), length));
|
||||
break;
|
||||
default:
|
||||
|
@ -606,27 +689,35 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
logf("scsi mode_sense_6 %d %X",lun,page_code);
|
||||
switch(page_code) {
|
||||
case 0x3f:
|
||||
/* All supported pages Since we support only one this is easy*/
|
||||
tb.mode_sense_data_6->mode_data_length=sizeof(struct mode_sense_data_6)-1;
|
||||
tb.mode_sense_data_6->medium_type=0;
|
||||
tb.mode_sense_data_6->device_specific=0;
|
||||
tb.mode_sense_data_6->block_descriptor_length=sizeof(struct mode_sense_block_descriptor_shortlba);
|
||||
tb.mode_sense_data_6->block_descriptor.density_code=0;
|
||||
tb.mode_sense_data_6->block_descriptor.reserved=0;
|
||||
/* All supported pages. */
|
||||
tb.ms_data_6->mode_data_length =
|
||||
sizeof(struct mode_sense_data_6)-1;
|
||||
tb.ms_data_6->medium_type = 0;
|
||||
tb.ms_data_6->device_specific = 0;
|
||||
tb.ms_data_6->block_descriptor_length =
|
||||
sizeof(struct mode_sense_bdesc_shortlba);
|
||||
tb.ms_data_6->block_descriptor.density_code = 0;
|
||||
tb.ms_data_6->block_descriptor.reserved = 0;
|
||||
if(block_count/block_size_mult > 0xffffff){
|
||||
tb.mode_sense_data_6->block_descriptor.number_of_blocks[0]=0xff;
|
||||
tb.mode_sense_data_6->block_descriptor.number_of_blocks[1]=0xff;
|
||||
tb.mode_sense_data_6->block_descriptor.number_of_blocks[2]=0xff;
|
||||
tb.ms_data_6->block_descriptor.num_blocks[0] = 0xff;
|
||||
tb.ms_data_6->block_descriptor.num_blocks[1] = 0xff;
|
||||
tb.ms_data_6->block_descriptor.num_blocks[2] = 0xff;
|
||||
}
|
||||
else {
|
||||
tb.mode_sense_data_6->block_descriptor.number_of_blocks[0]=((block_count/block_size_mult) & 0xff0000)>>16;
|
||||
tb.mode_sense_data_6->block_descriptor.number_of_blocks[1]=((block_count/block_size_mult) & 0x00ff00)>>8;
|
||||
tb.mode_sense_data_6->block_descriptor.number_of_blocks[2]=((block_count/block_size_mult) & 0x0000ff);
|
||||
tb.ms_data_6->block_descriptor.num_blocks[0] =
|
||||
((block_count/block_size_mult) & 0xff0000)>>16;
|
||||
tb.ms_data_6->block_descriptor.num_blocks[1] =
|
||||
((block_count/block_size_mult) & 0x00ff00)>>8;
|
||||
tb.ms_data_6->block_descriptor.num_blocks[2] =
|
||||
((block_count/block_size_mult) & 0x0000ff);
|
||||
}
|
||||
tb.mode_sense_data_6->block_descriptor.block_size[0]=((block_size*block_size_mult) & 0xff0000)>>16;
|
||||
tb.mode_sense_data_6->block_descriptor.block_size[1]=((block_size*block_size_mult) & 0x00ff00)>>8;
|
||||
tb.mode_sense_data_6->block_descriptor.block_size[2]=((block_size*block_size_mult) & 0x0000ff);
|
||||
send_command_result(tb.mode_sense_data_6,
|
||||
tb.ms_data_6->block_descriptor.block_size[0] =
|
||||
((block_size*block_size_mult) & 0xff0000)>>16;
|
||||
tb.ms_data_6->block_descriptor.block_size[1] =
|
||||
((block_size*block_size_mult) & 0x00ff00)>>8;
|
||||
tb.ms_data_6->block_descriptor.block_size[2] =
|
||||
((block_size*block_size_mult) & 0x0000ff);
|
||||
send_command_result(tb.ms_data_6,
|
||||
MIN(sizeof(struct mode_sense_data_6), length));
|
||||
break;
|
||||
default:
|
||||
|
@ -641,8 +732,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
|
||||
case SCSI_START_STOP_UNIT:
|
||||
logf("scsi start_stop unit %d",lun);
|
||||
if((cbw->command_block[4] & 0xf0) == 0) /* Process start and eject bits */
|
||||
{
|
||||
if((cbw->command_block[4] & 0xf0) == 0)
|
||||
{ /* Process start and eject bits */
|
||||
if((cbw->command_block[4] & 0x01) == 0 &&
|
||||
(cbw->command_block[4] & 0x02) != 0) /* Stop and eject */
|
||||
{
|
||||
|
@ -661,10 +752,13 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
logf("scsi read_format_capacity %d",lun);
|
||||
if(lun_present) {
|
||||
tb.format_capacity_data->following_length=htobe32(8);
|
||||
/* Careful: "block count" actually means "number of last block" */
|
||||
tb.format_capacity_data->block_count = htobe32(block_count/block_size_mult - 1);
|
||||
tb.format_capacity_data->block_size = htobe32(block_size*block_size_mult);
|
||||
tb.format_capacity_data->block_size |= SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA;
|
||||
/* "block count" actually means "number of last block" */
|
||||
tb.format_capacity_data->block_count =
|
||||
htobe32(block_count/block_size_mult - 1);
|
||||
tb.format_capacity_data->block_size =
|
||||
htobe32(block_size*block_size_mult);
|
||||
tb.format_capacity_data->block_size |=
|
||||
SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA;
|
||||
|
||||
send_command_result(tb.format_capacity_data,
|
||||
MIN(sizeof(struct format_capacity), length));
|
||||
|
@ -682,11 +776,14 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
logf("scsi read_capacity %d",lun);
|
||||
|
||||
if(lun_present) {
|
||||
/* Careful: "block count" actually means "number of last block" */
|
||||
tb.capacity_data->block_count = htobe32(block_count/block_size_mult - 1);
|
||||
tb.capacity_data->block_size = htobe32(block_size*block_size_mult);
|
||||
/* "block count" actually means "number of last block" */
|
||||
tb.capacity_data->block_count =
|
||||
htobe32(block_count/block_size_mult - 1);
|
||||
tb.capacity_data->block_size =
|
||||
htobe32(block_size*block_size_mult);
|
||||
|
||||
send_command_result(tb.capacity_data, MIN(sizeof(struct capacity), length));
|
||||
send_command_result(tb.capacity_data,
|
||||
MIN(sizeof(struct capacity), length));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -707,30 +804,32 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
cur_sense_data.ascq=0;
|
||||
break;
|
||||
}
|
||||
current_cmd.data[0] = tb.transfer_buffer;
|
||||
current_cmd.data[1] = &tb.transfer_buffer[BUFFER_SIZE];
|
||||
current_cmd.data_select=0;
|
||||
current_cmd.sector = block_size_mult *
|
||||
cur_cmd.data[0] = tb.transfer_buffer;
|
||||
cur_cmd.data[1] = &tb.transfer_buffer[BUFFER_SIZE];
|
||||
cur_cmd.data_select=0;
|
||||
cur_cmd.sector = block_size_mult *
|
||||
(cbw->command_block[2] << 24 |
|
||||
cbw->command_block[3] << 16 |
|
||||
cbw->command_block[4] << 8 |
|
||||
cbw->command_block[5] );
|
||||
current_cmd.count = block_size_mult *
|
||||
cur_cmd.count = block_size_mult *
|
||||
(cbw->command_block[7] << 8 |
|
||||
cbw->command_block[8]);
|
||||
|
||||
//logf("scsi read %d %d", current_cmd.sector, current_cmd.count);
|
||||
//logf("scsi read %d %d", cur_cmd.sector, cur_cmd.count);
|
||||
|
||||
if((current_cmd.sector + current_cmd.count) > block_count) {
|
||||
if((cur_cmd.sector + cur_cmd.count) > block_count) {
|
||||
send_csw(UMS_STATUS_FAIL);
|
||||
cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST;
|
||||
cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE;
|
||||
cur_sense_data.ascq=0;
|
||||
}
|
||||
else {
|
||||
current_cmd.last_result = ata_read_sectors(IF_MV2(current_cmd.lun,) current_cmd.sector,
|
||||
MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count),
|
||||
current_cmd.data[current_cmd.data_select]);
|
||||
cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,)
|
||||
cur_cmd.sector,
|
||||
MIN(BUFFER_SIZE/SECTOR_SIZE,
|
||||
cur_cmd.count),
|
||||
cur_cmd.data[cur_cmd.data_select]);
|
||||
send_and_read_next();
|
||||
}
|
||||
break;
|
||||
|
@ -744,34 +843,35 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
cur_sense_data.ascq=0;
|
||||
break;
|
||||
}
|
||||
current_cmd.data[0] = tb.transfer_buffer;
|
||||
current_cmd.data[1] = &tb.transfer_buffer[BUFFER_SIZE];
|
||||
current_cmd.data_select=0;
|
||||
current_cmd.sector = block_size_mult *
|
||||
cur_cmd.data[0] = tb.transfer_buffer;
|
||||
cur_cmd.data[1] = &tb.transfer_buffer[BUFFER_SIZE];
|
||||
cur_cmd.data_select=0;
|
||||
cur_cmd.sector = block_size_mult *
|
||||
(cbw->command_block[2] << 24 |
|
||||
cbw->command_block[3] << 16 |
|
||||
cbw->command_block[4] << 8 |
|
||||
cbw->command_block[5] );
|
||||
current_cmd.count = block_size_mult *
|
||||
cur_cmd.count = block_size_mult *
|
||||
(cbw->command_block[7] << 8 |
|
||||
cbw->command_block[8]);
|
||||
/* expect data */
|
||||
if((current_cmd.sector + current_cmd.count) > block_count) {
|
||||
if((cur_cmd.sector + cur_cmd.count) > block_count) {
|
||||
send_csw(UMS_STATUS_FAIL);
|
||||
cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST;
|
||||
cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE;
|
||||
cur_sense_data.ascq=0;
|
||||
}
|
||||
else {
|
||||
receive_block_data(current_cmd.data[0],
|
||||
MIN(BUFFER_SIZE,current_cmd.count*SECTOR_SIZE));
|
||||
receive_block_data(cur_cmd.data[0],
|
||||
MIN(BUFFER_SIZE,
|
||||
cur_cmd.count*SECTOR_SIZE));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
logf("scsi unknown cmd %x",cbw->command_block[0x0]);
|
||||
usb_drv_stall(EP_MASS_STORAGE, true,true);
|
||||
usb_drv_stall(usb_endpoint, true,true);
|
||||
send_csw(UMS_STATUS_FAIL);
|
||||
break;
|
||||
}
|
||||
|
@ -779,30 +879,31 @@ static void handle_scsi(struct command_block_wrapper* cbw)
|
|||
|
||||
static void send_block_data(void *data,int size)
|
||||
{
|
||||
usb_drv_send_nonblocking(EP_MASS_STORAGE, data,size);
|
||||
usb_drv_send_nonblocking(usb_endpoint, data,size);
|
||||
state = SENDING_BLOCKS;
|
||||
}
|
||||
|
||||
static void send_command_result(void *data,int size)
|
||||
{
|
||||
usb_drv_send_nonblocking(EP_MASS_STORAGE, data,size);
|
||||
usb_drv_send_nonblocking(usb_endpoint, data,size);
|
||||
state = SENDING_RESULT;
|
||||
}
|
||||
|
||||
static void receive_block_data(void *data,int size)
|
||||
{
|
||||
usb_drv_recv(EP_MASS_STORAGE, data, size);
|
||||
usb_drv_recv(usb_endpoint, data, size);
|
||||
state = RECEIVING_BLOCKS;
|
||||
}
|
||||
|
||||
static void send_csw(int status)
|
||||
{
|
||||
tb.csw->signature = htole32(CSW_SIGNATURE);
|
||||
tb.csw->tag = current_cmd.tag;
|
||||
tb.csw->tag = cur_cmd.tag;
|
||||
tb.csw->data_residue = 0;
|
||||
tb.csw->status = status;
|
||||
|
||||
usb_drv_send_nonblocking(EP_MASS_STORAGE, tb.csw, sizeof(struct command_status_wrapper));
|
||||
usb_drv_send_nonblocking(usb_endpoint, tb.csw,
|
||||
sizeof(struct command_status_wrapper));
|
||||
state = SENDING_CSW;
|
||||
//logf("CSW: %X",status);
|
||||
|
||||
|
@ -866,7 +967,8 @@ static void identify2inquiry(int lun)
|
|||
tb.inquiry->DeviceTypeModifier = DEVICE_REMOVABLE;
|
||||
#endif
|
||||
#endif
|
||||
/* Mac OSX 10.5 doesn't like this driver if DEVICE_REMOVABLE is not set */
|
||||
/* Mac OSX 10.5 doesn't like this driver if DEVICE_REMOVABLE is not set.
|
||||
TODO : this can probably be solved by providing caching mode page */
|
||||
tb.inquiry->DeviceTypeModifier = DEVICE_REMOVABLE;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
|
||||
#include "usb_ch9.h"
|
||||
|
||||
int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size,
|
||||
int interface_number,int endpoint);
|
||||
void usb_storage_init_connection(int interface,int endpoint);
|
||||
void usb_storage_init(void);
|
||||
void usb_storage_transfer_complete(bool in,int state,int length);
|
||||
bool usb_storage_control_request(struct usb_ctrlrequest* req);
|
||||
|
|
Loading…
Reference in a new issue