USBqemu: upgrade qemu core from version 0.12.5 to 0.15. Now its up to date with the latest qemu release.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4904 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gigaherz 2011-09-04 15:24:23 +00:00
parent 34edc05ab8
commit ef50bc898d
15 changed files with 1655 additions and 1241 deletions

View File

@ -142,14 +142,18 @@ s32 CALLBACK USBinit() {
}
qemu_ohci = ohci_create(0x1f801600,2);
qemu_ohci->rhport[0].port.attach(&(qemu_ohci->rhport[0].port),usb_keyboard_init());
qemu_ohci->rhport[0].port.dev = usb_keyboard_init();
qemu_ohci->rhport[0].port.ops->attach(&(qemu_ohci->rhport[0].port));
return 0;
}
void CALLBACK USBshutdown() {
qemu_ohci->rhport[0].port.dev->info->handle_destroy(qemu_ohci->rhport[0].port.dev);
USBDevice* device = qemu_ohci->rhport[0].port.dev;
qemu_ohci->rhport[0].port.ops->detach(&(qemu_ohci->rhport[0].port));
device->info->handle_destroy(qemu_ohci->rhport[0].port.dev);
free(qemu_ohci);
@ -237,27 +241,66 @@ void CALLBACK USBsetRAM(void *mem) {
// extended funcs
char USBfreezeID[] = "USB STv0";
char USBfreezeID[] = "USBqemu01";
typedef struct {
char freezeID[10];
OHCIState t;
int extraData; // for future expansion with the device state
} USBfreezeData;
s32 CALLBACK USBfreeze(int mode, freezeData *data) {
USBfreezeData *usbd;
USBfreezeData usbd;
if (mode == FREEZE_LOAD) {
usbd = (USBfreezeData*)data->data;
if (data->size != sizeof(USBfreezeData)) return -1;
if (mode == FREEZE_LOAD)
{
if(data->size < sizeof(USBfreezeData))
{
SysMessage("ERROR: Unable to load freeze data! Got %d bytes, expected >= %d.", data->size, sizeof(USBfreezeData));
return -1;
}
usbd = *(USBfreezeData*)data->data;
usbd.freezeID[9] = 0;
if( strcmp(usbd.freezeID, USBfreezeID) != 0)
{
SysMessage("ERROR: Unable to load freeze data! Found ID '%s', expected ID '%s'.", usbd.freezeID, USBfreezeID);
return -1;
}
if (data->size != sizeof(USBfreezeData))
return -1;
memcpy(qemu_ohci, usbd, sizeof(OHCIState));
} else
if (mode == FREEZE_SAVE) {
for(int i=0; i< qemu_ohci->num_ports; i++)
{
usbd.t.rhport[i].port.opaque = qemu_ohci;
usbd.t.rhport[i].port.ops = qemu_ohci->rhport[i].port.ops;
usbd.t.rhport[i].port.dev = qemu_ohci->rhport[i].port.dev; // pointers
}
*qemu_ohci = usbd.t;
// WARNING: TODO: Load the state of the attached devices!
}
else if (mode == FREEZE_SAVE)
{
data->size = sizeof(USBfreezeData);
data->data = (s8*)malloc(data->size);
if (data->data == NULL) return -1;
usbd = (USBfreezeData*)data->data;
memcpy(usbd, qemu_ohci, sizeof(OHCIState));
if (data->data == NULL)
return -1;
strcpy(usbd.freezeID, USBfreezeID);
usbd.t = *qemu_ohci;
for(int i=0; i< qemu_ohci->num_ports; i++)
{
usbd.t.rhport[i].port.ops = NULL; // pointers
usbd.t.rhport[i].port.opaque = NULL; // pointers
usbd.t.rhport[i].port.dev = NULL; // pointers
}
// WARNING: TODO: Save the state of the attached devices!
}
return 0;

View File

@ -57,7 +57,8 @@ void LoadConfig();
extern FILE *usbLog;
void __Log(char *fmt, ...);
void SysMessage(char *fmt, ...);
extern void SysMessage(const char *fmt, ...);
extern void SysMessage(const wchar_t *fmt, ...);
extern HWND gsWindowHandle;

View File

@ -64,7 +64,7 @@ void CfgSetSettingsDir( const char* dir )
}
/*| Config File Format: |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*\
/*¯| Config File Format: |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯*\
+--+---------------------+------------------------+
| |
| Option=Value |
@ -76,7 +76,7 @@ void CfgSetSettingsDir( const char* dir )
| All Values are limited to 255 chars. |
| |
+-------------------------------------------------+
\*_____________________________________________*/
\*______________________________________________*/
void CfgWriteBool(const TCHAR* Section, const TCHAR* Name, bool Value)
@ -136,7 +136,6 @@ int CfgReadInt(const TCHAR* Section, const TCHAR* Name,int Default)
void CfgReadStr(const TCHAR* Section, const TCHAR* Name, TCHAR* Data, int DataSize, const TCHAR* Default)
{
wchar_t workspace[512];
int chars = GetPrivateProfileString(Section,Name,L"",Data,DataSize,CfgFile);
if(!chars)

View File

@ -3,7 +3,6 @@
#include <tchar.h>
extern void CfgSetSettingsDir( const char* dir );
extern void CfgSetLogDir( const char* dir );
extern bool CfgFindName( const TCHAR *Section, const TCHAR* Name);

View File

@ -126,7 +126,9 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\qemu-usb\usb-hub.cpp" />
<ClCompile Include="..\qemu-usb\usb-hub.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\qemu-usb\usb-kbd.cpp" />
<ClCompile Include="..\usb-mic\usb-mic-dummy.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>

View File

@ -28,7 +28,6 @@ typedef uint32_t target_phys_addr_t;
typedef struct {
//USBBus bus;
//qemu_irq irq;
enum ohci_type type;
int mem;
int num_ports;
const char *name;
@ -91,19 +90,8 @@ struct ohci_hcca {
uint32_t done;
};
extern int64_t usb_frame_time;
extern int64_t usb_bit_time;
enum ohci_type {
OHCI_TYPE_PCI,
OHCI_TYPE_PXA,
OHCI_TYPE_SM501,
};
int64_t get_ticks_per_sec();
static void ohci_bus_stop(OHCIState *ohci);
static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
/* Bitfields for the first word of an Endpoint Desciptor. */
#define OHCI_ED_FA_SHIFT 0
@ -282,6 +270,7 @@ struct ohci_iso_td {
#define OHCI_HRESET_FSBIR (1 << 0)
int64_t get_ticks_per_sec();
int64_t get_clock();

View File

@ -26,9 +26,35 @@
#include "USBinternal.h"
//#include "usb.h"
#include <assert.h>
void usb_attach(USBPort *port, USBDevice *dev)
{
port->attach(port, dev);
if (dev != NULL) {
/* attach */
if (port->dev) {
usb_attach(port, NULL);
}
dev->port = port;
port->dev = dev;
port->ops->attach(port);
usb_send_msg(dev, USB_MSG_ATTACH);
} else {
/* detach */
dev = port->dev;
assert(dev);
port->ops->detach(port);
usb_send_msg(dev, USB_MSG_DETACH);
dev->port = NULL;
port->dev = NULL;
}
}
void usb_wakeup(USBDevice *dev)
{
if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
dev->port->ops->wakeup(dev->port);
}
}
/**********************/
@ -38,9 +64,10 @@ void usb_attach(USBPort *port, USBDevice *dev)
protocol)
*/
#define SETUP_STATE_IDLE 0
#define SETUP_STATE_DATA 1
#define SETUP_STATE_ACK 2
#define SETUP_STATE_IDLE 0
#define SETUP_STATE_SETUP 1
#define SETUP_STATE_DATA 2
#define SETUP_STATE_ACK 3
static int do_token_setup(USBDevice *s, USBPacket *p)
{
@ -57,10 +84,14 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
if (s->setup_buf[0] & USB_DIR_IN) {
ret = s->info->handle_control(s, request, value, index,
ret = s->info->handle_control(s, p, request, value, index,
s->setup_len, s->data_buf);
if (ret == USB_RET_ASYNC) {
s->setup_state = SETUP_STATE_SETUP;
return USB_RET_ASYNC;
}
if (ret < 0)
return ret;
@ -68,6 +99,12 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
s->setup_len = ret;
s->setup_state = SETUP_STATE_DATA;
} else {
if (s->setup_len > sizeof(s->data_buf)) {
fprintf(stderr,
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
s->setup_len, sizeof(s->data_buf));
return USB_RET_STALL;
}
if (s->setup_len == 0)
s->setup_state = SETUP_STATE_ACK;
else
@ -92,9 +129,12 @@ static int do_token_in(USBDevice *s, USBPacket *p)
switch(s->setup_state) {
case SETUP_STATE_ACK:
if (!(s->setup_buf[0] & USB_DIR_IN)) {
s->setup_state = SETUP_STATE_IDLE;
ret = s->info->handle_control(s, request, value, index,
ret = s->info->handle_control(s, p, request, value, index,
s->setup_len, s->data_buf);
if (ret == USB_RET_ASYNC) {
return USB_RET_ASYNC;
}
s->setup_state = SETUP_STATE_IDLE;
if (ret > 0)
return 0;
return ret;
@ -169,6 +209,9 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
switch(p->pid) {
case USB_MSG_ATTACH:
s->state = USB_STATE_ATTACHED;
if (s->info->handle_attach) {
s->info->handle_attach(s);
}
return 0;
case USB_MSG_DETACH:
@ -179,7 +222,9 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
s->remote_wakeup = 0;
s->addr = 0;
s->state = USB_STATE_DEFAULT;
s->info->handle_reset(s);
if (s->info->handle_reset) {
s->info->handle_reset(s);
}
return 0;
}
@ -202,6 +247,36 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
}
}
/* ctrl complete function for devices which use usb_generic_handle_packet and
may return USB_RET_ASYNC from their handle_control callback. Device code
which does this *must* call this function instead of the normal
usb_packet_complete to complete their async control packets. */
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
{
if (p->len < 0) {
s->setup_state = SETUP_STATE_IDLE;
}
switch (s->setup_state) {
case SETUP_STATE_SETUP:
if (p->len < s->setup_len) {
s->setup_len = p->len;
}
s->setup_state = SETUP_STATE_DATA;
p->len = 8;
break;
case SETUP_STATE_ACK:
s->setup_state = SETUP_STATE_IDLE;
p->len = 0;
break;
default:
break;
}
usb_packet_complete(s, p);
}
/* XXX: fix overflow */
int set_usb_string(uint8_t *buf, const char *str)
{
@ -223,9 +298,54 @@ int set_usb_string(uint8_t *buf, const char *str)
void usb_send_msg(USBDevice *dev, int msg)
{
USBPacket p;
int ret;
memset(&p, 0, sizeof(p));
p.pid = msg;
dev->info->handle_packet(dev, &p);
ret = usb_handle_packet(dev, &p);
/* This _must_ be synchronous */
assert(ret != USB_RET_ASYNC);
}
/* Hand over a packet to a device for processing. Return value
USB_RET_ASYNC indicates the processing isn't finished yet, the
driver will call usb_packet_complete() when done processing it. */
int usb_handle_packet(USBDevice *dev, USBPacket *p)
{
int ret;
assert(p->owner == NULL);
ret = dev->info->handle_packet(dev, p);
if (ret == USB_RET_ASYNC) {
if (p->owner == NULL) {
p->owner = dev;
} else {
/* We'll end up here when usb_handle_packet is called
* recursively due to a hub being in the chain. Nothing
* to do. Leave p->owner pointing to the device, not the
* hub. */;
}
}
return ret;
}
/* Notify the controller that an async packet is complete. This should only
be called for packets previously deferred by returning USB_RET_ASYNC from
handle_packet. */
void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
/* Note: p->owner != dev is possible in case dev is a hub */
assert(p->owner != NULL);
dev->port->ops->complete(dev->port, p);
p->owner = NULL;
}
/* Cancel an active packet. The packed must have been deferred by
returning USB_RET_ASYNC from handle_packet, and not yet
completed. */
void usb_cancel_packet(USBPacket * p)
{
assert(p->owner != NULL);
p->owner->info->cancel_packet(p->owner, p);
p->owner = NULL;
}

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,7 @@
//#define DEBUG
#define MAX_PORTS 8
#define NUM_PORTS 8
typedef struct USBHubPort {
USBPort port;
@ -35,8 +35,7 @@ typedef struct USBHubPort {
typedef struct USBHubState {
USBDevice dev;
int nb_ports;
USBHubPort ports[MAX_PORTS];
USBHubPort ports[NUM_PORTS];
} USBHubState;
#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
@ -82,72 +81,59 @@ typedef struct USBHubState {
/* same as Linux kernel root hubs */
static const uint8_t qemu_hub_dev_descriptor[] = {
0x12, /* u8 bLength; */
0x01, /* u8 bDescriptorType; Device */
0x10, 0x01, /* u16 bcdUSB; v1.1 */
0x09, /* u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* u8 bDeviceSubClass; */
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
0x08, /* u8 bMaxPacketSize0; 8 Bytes */
0x00, 0x00, /* u16 idVendor; */
0x00, 0x00, /* u16 idProduct; */
0x01, 0x01, /* u16 bcdDevice */
0x03, /* u8 iManufacturer; */
0x02, /* u8 iProduct; */
0x01, /* u8 iSerialNumber; */
0x01 /* u8 bNumConfigurations; */
enum {
STR_MANUFACTURER = 1,
STR_PRODUCT,
STR_SERIALNUMBER,
};
/* XXX: patch interrupt size */
static const uint8_t qemu_hub_config_descriptor[] = {
static const USBDescStrings desc_strings = {
[STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
[STR_PRODUCT] = "QEMU USB Hub",
[STR_SERIALNUMBER] = "314159",
};
/* one configuration */
0x09, /* u8 bLength; */
0x02, /* u8 bDescriptorType; Configuration */
0x19, 0x00, /* u16 wTotalLength; */
0x01, /* u8 bNumInterfaces; (1) */
0x01, /* u8 bConfigurationValue; */
0x00, /* u8 iConfiguration; */
0xc0, /* u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5: Remote wakeup,
4..0: resvd */
0x00, /* u8 MaxPower; */
static const USBDescIface desc_iface_hub = {
.bInterfaceNumber = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_HUB,
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_IN | 0x01,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = 1 + (NUM_PORTS + 7) / 8,
.bInterval = 0xff,
},
}
};
/* USB 1.1:
* USB 2.0, single TT organization (mandatory):
* one interface, protocol 0
*
* USB 2.0, multiple TT organization (optional):
* two interfaces, protocols 1 (like single TT)
* and 2 (multiple TT mode) ... config is
* sometimes settable
* NOT IMPLEMENTED
*/
static const USBDescDevice desc_device_hub = {
.bcdUSB = 0x0110,
.bDeviceClass = USB_CLASS_HUB,
.bMaxPacketSize0 = 8,
.bNumConfigurations = 1,
.confs = (USBDescConfig[]) {
{
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.bmAttributes = 0xe0,
.nif = 1,
.ifs = &desc_iface_hub,
},
},
};
/* one interface */
0x09, /* u8 if_bLength; */
0x04, /* u8 if_bDescriptorType; Interface */
0x00, /* u8 if_bInterfaceNumber; */
0x00, /* u8 if_bAlternateSetting; */
0x01, /* u8 if_bNumEndpoints; */
0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */
0x00, /* u8 if_bInterfaceSubClass; */
0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
0x00, /* u8 if_iInterface; */
/* one endpoint (status change endpoint) */
0x07, /* u8 ep_bLength; */
0x05, /* u8 ep_bDescriptorType; Endpoint */
0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* u8 ep_bmAttributes; Interrupt */
0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
static const USBDesc desc_hub = {
.id = {
.idVendor = 0,
.idProduct = 0,
.bcdDevice = 0x0101,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT,
.iSerialNumber = STR_SERIALNUMBER,
},
.full = &desc_device_hub,
.str = desc_strings,
};
static const uint8_t qemu_hub_hub_descriptor[] =
@ -163,37 +149,75 @@ static const uint8_t qemu_hub_hub_descriptor[] =
/* DeviceRemovable and PortPwrCtrlMask patched in later */
};
static void usb_hub_attach(USBPort *port1, USBDevice *dev)
static void usb_hub_attach(USBPort *port1)
{
USBHubState *s = (USBHubState *)port1->opaque;
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
if (dev) {
if (port->port.dev)
usb_attach(port1, NULL);
port->wPortStatus |= PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (dev->speed == USB_SPEED_LOW)
port->wPortStatus |= PORT_STAT_LOW_SPEED;
else
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
port->port.dev = dev;
/* send the attach message */
usb_send_msg(dev, USB_MSG_ATTACH);
port->wPortStatus |= PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->port.dev->speed == USB_SPEED_LOW) {
port->wPortStatus |= PORT_STAT_LOW_SPEED;
} else {
dev = port->port.dev;
if (dev) {
port->wPortStatus &= ~PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->wPortStatus & PORT_STAT_ENABLE) {
port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE;
}
/* send the detach message */
usb_send_msg(dev, USB_MSG_DETACH);
port->port.dev = NULL;
}
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
}
}
static void usb_hub_detach(USBPort *port1)
{
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
/* Let upstream know the device on this port is gone */
s->dev.port->ops->child_detach(s->dev.port, port1->dev);
port->wPortStatus &= ~PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->wPortStatus & PORT_STAT_ENABLE) {
port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE;
}
}
static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
{
USBHubState *s = port1->opaque;
/* Pass along upstream */
s->dev.port->ops->child_detach(s->dev.port, child);
}
static void usb_hub_wakeup(USBPort *port1)
{
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
if (port->wPortStatus & PORT_STAT_SUSPEND) {
port->wPortChange |= PORT_STAT_C_SUSPEND;
usb_wakeup(&s->dev);
}
}
static void usb_hub_complete(USBPort *port, USBPacket *packet)
{
USBHubState *s = port->opaque;
/*
* Just pass it along upstream for now.
*
* If we ever inplement usb 2.0 split transactions this will
* become a little more complicated ...
*/
usb_packet_complete(&s->dev, packet);
}
static void usb_hub_handle_attach(USBDevice *dev)
{
USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
int i;
for (i = 0; i < NUM_PORTS; i++) {
usb_port_location(&s->ports[i].port, dev->port, i+1);
}
}
@ -202,99 +226,24 @@ static void usb_hub_handle_reset(USBDevice *dev)
/* XXX: do it */
}
static int usb_hub_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBHubState *s = (USBHubState *)dev;
int ret;
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
}
switch(request) {
case DeviceRequest | USB_REQ_GET_STATUS:
data[0] = (1 << USB_DEVICE_SELF_POWERED) |
(dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
data[1] = 0x00;
ret = 2;
break;
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
if (value == USB_DEVICE_REMOTE_WAKEUP) {
dev->remote_wakeup = 0;
} else {
goto fail;
}
ret = 0;
break;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
if (value == 0 && index != 0x81) { /* clear ep halt */
goto fail;
}
ret = 0;
break;
case DeviceOutRequest | USB_REQ_SET_FEATURE:
if (value == USB_DEVICE_REMOTE_WAKEUP) {
dev->remote_wakeup = 1;
} else {
goto fail;
}
ret = 0;
break;
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
dev->addr = value;
ret = 0;
break;
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
switch(value >> 8) {
case USB_DT_DEVICE:
memcpy(data, qemu_hub_dev_descriptor,
sizeof(qemu_hub_dev_descriptor));
ret = sizeof(qemu_hub_dev_descriptor);
break;
case USB_DT_CONFIG:
memcpy(data, qemu_hub_config_descriptor,
sizeof(qemu_hub_config_descriptor));
/* status change endpoint size based on number
* of ports */
data[22] = (s->nb_ports + 1 + 7) / 8;
ret = sizeof(qemu_hub_config_descriptor);
break;
case USB_DT_STRING:
switch(value & 0xff) {
case 0:
/* language ids */
data[0] = 4;
data[1] = 3;
data[2] = 0x09;
data[3] = 0x04;
ret = 4;
break;
case 1:
/* serial number */
ret = set_usb_string(data, "314159");
break;
case 2:
/* product description */
ret = set_usb_string(data, "QEMU USB Hub");
break;
case 3:
/* vendor description */
ret = set_usb_string(data, "QEMU v0.12.5");
break;
default:
goto fail;
}
break;
default:
goto fail;
}
break;
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
data[0] = 1;
ret = 1;
break;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
ret = 0;
break;
case DeviceRequest | USB_REQ_GET_INTERFACE:
data[0] = 0;
ret = 1;
@ -314,8 +263,9 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
{
unsigned int n = index - 1;
USBHubPort *port;
if (n >= s->nb_ports)
if (n >= NUM_PORTS) {
goto fail;
}
port = &s->ports[n];
data[0] = port->wPortStatus;
data[1] = port->wPortStatus >> 8;
@ -337,8 +287,9 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
unsigned int n = index - 1;
USBHubPort *port;
USBDevice *dev;
if (n >= s->nb_ports)
if (n >= NUM_PORTS) {
goto fail;
}
port = &s->ports[n];
dev = port->port.dev;
switch(value) {
@ -365,11 +316,11 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
{
unsigned int n = index - 1;
USBHubPort *port;
USBDevice *dev;
if (n >= s->nb_ports)
if (n >= NUM_PORTS) {
goto fail;
}
port = &s->ports[n];
dev = port->port.dev;
switch(value) {
case PORT_ENABLE:
port->wPortStatus &= ~PORT_STAT_ENABLE;
@ -403,17 +354,17 @@ static int usb_hub_handle_control(USBDevice *dev, int request, int value,
unsigned int n, limit, var_hub_size = 0;
memcpy(data, qemu_hub_hub_descriptor,
sizeof(qemu_hub_hub_descriptor));
data[2] = s->nb_ports;
data[2] = NUM_PORTS;
/* fill DeviceRemovable bits */
limit = ((s->nb_ports + 1 + 7) / 8) + 7;
limit = ((NUM_PORTS + 1 + 7) / 8) + 7;
for (n = 7; n < limit; n++) {
data[n] = 0x00;
var_hub_size++;
}
/* fill PortPwrCtrlMask bits */
limit = limit + ((s->nb_ports + 7) / 8);
limit = limit + ((NUM_PORTS + 7) / 8);
for (;n < limit; n++) {
data[n] = 0xff;
var_hub_size++;
@ -442,14 +393,14 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
USBHubPort *port;
unsigned int status;
int i, n;
n = (s->nb_ports + 1 + 7) / 8;
n = (NUM_PORTS + 1 + 7) / 8;
if (p->len == 1) { /* FreeBSD workaround */
n = 1;
} else if (n > p->len) {
return USB_RET_BABBLE;
}
status = 0;
for(i = 0; i < s->nb_ports; i++) {
for(i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
if (port->wPortChange)
status |= (1 << (i + 1));
@ -481,11 +432,11 @@ static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
USBDevice *dev;
int i, ret;
for(i = 0; i < s->nb_ports; i++) {
for(i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
dev = port->port.dev;
if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
ret = dev->info->handle_packet(dev, p);
ret = usb_handle_packet(dev, p);
if (ret != USB_RET_NODEV) {
return ret;
}
@ -518,44 +469,79 @@ static void usb_hub_handle_destroy(USBDevice *dev)
USBHubState *s = (USBHubState *)dev;
int i;
//for (i = 0; i < s->nb_ports; i++) {
// usb_unregister_port(usb_bus_from_device(dev),
// &s->ports[i].port);
//}
for (i = 0; i < NUM_PORTS; i++) {
usb_unregister_port(usb_bus_from_device(dev),
&s->ports[i].port);
}
}
static USBPortOps usb_hub_port_ops = {
.attach = usb_hub_attach,
.detach = usb_hub_detach,
.child_detach = usb_hub_child_detach,
.wakeup = usb_hub_wakeup,
.complete = usb_hub_complete,
};
static int usb_hub_initfn(USBDevice *dev)
{
USBHubState *s = (USBHubState*)dev;
USBHubState *s = DO_UPCAST(USBHubState, dev, dev);
USBHubPort *port;
int i;
s->dev.speed = USB_SPEED_FULL,
s->nb_ports = MAX_PORTS; /* FIXME: make configurable */
for (i = 0; i < s->nb_ports; i++) {
usb_desc_init(dev);
for (i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
//usb_register_port(usb_bus_from_device(dev),
// &port->port, s, i, usb_hub_attach);
usb_register_port(usb_bus_from_device(dev),
&port->port, s, i, &usb_hub_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
port->wPortStatus = PORT_STAT_POWER;
port->wPortChange = 0;
}
return 0;
}
static const VMStateDescription vmstate_usb_hub_port = {
.name = "usb-hub-port",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField []) {
VMSTATE_UINT16(wPortStatus, USBHubPort),
VMSTATE_UINT16(wPortChange, USBHubPort),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_usb_hub = {
.name = "usb-hub",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField []) {
VMSTATE_USB_DEVICE(dev, USBHubState),
VMSTATE_STRUCT_ARRAY(ports, USBHubState, NUM_PORTS, 0,
vmstate_usb_hub_port, USBHubPort),
VMSTATE_END_OF_LIST()
}
};
static struct USBDeviceInfo hub_info = {
usb_hub_initfn,
usb_hub_handle_packet,
usb_hub_handle_destroy,
usb_hub_handle_reset,
usb_hub_handle_control,
usb_hub_handle_data,
"QEMU USB Hub",
.product_desc = "QEMU USB Hub",
.qdev.name = "usb-hub",
.qdev.fw_name = "hub",
.qdev.size = sizeof(USBHubState),
.qdev.vmsd = &vmstate_usb_hub,
.usb_desc = &desc_hub,
.init = usb_hub_initfn,
.handle_packet = usb_hub_handle_packet,
.handle_attach = usb_hub_handle_attach,
.handle_reset = usb_hub_handle_reset,
.handle_control = usb_hub_handle_control,
.handle_data = usb_hub_handle_data,
.handle_destroy = usb_hub_handle_destroy,
};
static void usb_hub_register_devices(void)
{
//usb_qdev_register(&hub_info);
usb_qdev_register(&hub_info);
}
//device_init(usb_hub_register_devices)
device_init(usb_hub_register_devices)

View File

@ -697,8 +697,8 @@ static void usb_keyboard_handle_reset(USBDevice *dev)
USBKeyboardState *s = (USBKeyboardState *)dev;
}
static int usb_keyboard_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int usb_keyboard_handle_control(USBDevice *dev, USBPacket *p, int request, int value,
int index, int length, uint8_t *data)
{
USBKeyboardState *s = (USBKeyboardState *)dev;
int ret = 0;

View File

@ -4,17 +4,19 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the LGPL.
* This code is licensed under the LGPL.
*/
#include "qemu-common.h"
#include "qemu-option.h"
#include "qemu-config.h"
#include "usb.h"
#include "block.h"
#include "usb-desc.h"
#include "scsi.h"
#include "console.h"
#include "monitor.h"
#include "sysemu.h"
#include "blockdev.h"
//#define DEBUG_MSD
@ -31,7 +33,7 @@ do { printf("usb-msd: " fmt , ## __VA_ARGS__); } while (0)
enum USBMSDMode {
USB_MSDM_CBW, /* Command Block. */
USB_MSDM_DATAOUT, /* Tranfer data to device. */
USB_MSDM_DATAOUT, /* Transfer data to device. */
USB_MSDM_DATAIN, /* Transfer data from device. */
USB_MSDM_CSW /* Command Status. */
};
@ -46,9 +48,12 @@ typedef struct {
uint32_t data_len;
uint32_t residue;
uint32_t tag;
SCSIRequest *req;
SCSIBus bus;
DriveInfo *dinfo;
BlockConf conf;
char *serial;
SCSIDevice *scsi_dev;
uint32_t removable;
int result;
/* For async completion. */
USBPacket *packet;
@ -71,69 +76,104 @@ struct usb_msd_csw {
uint8_t status;
};
static const uint8_t qemu_msd_dev_descriptor[] = {
0x12, /* u8 bLength; */
0x01, /* u8 bDescriptorType; Device */
0x00, 0x01, /* u16 bcdUSB; v1.0 */
0x00, /* u8 bDeviceClass; */
0x00, /* u8 bDeviceSubClass; */
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
0x08, /* u8 bMaxPacketSize0; 8 Bytes */
/* Vendor and product id are arbitrary. */
0x00, 0x00, /* u16 idVendor; */
0x00, 0x00, /* u16 idProduct; */
0x00, 0x00, /* u16 bcdDevice */
0x01, /* u8 iManufacturer; */
0x02, /* u8 iProduct; */
0x03, /* u8 iSerialNumber; */
0x01 /* u8 bNumConfigurations; */
enum {
STR_MANUFACTURER = 1,
STR_PRODUCT,
STR_SERIALNUMBER,
STR_CONFIG_FULL,
STR_CONFIG_HIGH,
};
static const uint8_t qemu_msd_config_descriptor[] = {
static const USBDescStrings desc_strings = {
[STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
[STR_PRODUCT] = "QEMU USB HARDDRIVE",
[STR_SERIALNUMBER] = "1",
[STR_CONFIG_FULL] = "Full speed config (usb 1.1)",
[STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
};
/* one configuration */
0x09, /* u8 bLength; */
0x02, /* u8 bDescriptorType; Configuration */
0x20, 0x00, /* u16 wTotalLength; */
0x01, /* u8 bNumInterfaces; (1) */
0x01, /* u8 bConfigurationValue; */
0x00, /* u8 iConfiguration; */
0xc0, /* u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5: Remote wakeup,
4..0: resvd */
0x00, /* u8 MaxPower; */
static const USBDescIface desc_iface_full = {
.bInterfaceNumber = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
.bInterfaceSubClass = 0x06, /* SCSI */
.bInterfaceProtocol = 0x50, /* Bulk */
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_IN | 0x01,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 64,
},{
.bEndpointAddress = USB_DIR_OUT | 0x02,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 64,
},
}
};
/* one interface */
0x09, /* u8 if_bLength; */
0x04, /* u8 if_bDescriptorType; Interface */
0x00, /* u8 if_bInterfaceNumber; */
0x00, /* u8 if_bAlternateSetting; */
0x02, /* u8 if_bNumEndpoints; */
0x08, /* u8 if_bInterfaceClass; MASS STORAGE */
0x06, /* u8 if_bInterfaceSubClass; SCSI */
0x50, /* u8 if_bInterfaceProtocol; Bulk Only */
0x00, /* u8 if_iInterface; */
static const USBDescDevice desc_device_full = {
.bcdUSB = 0x0200,
.bMaxPacketSize0 = 8,
.bNumConfigurations = 1,
.confs = (USBDescConfig[]) {
{
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = STR_CONFIG_FULL,
.bmAttributes = 0xc0,
.nif = 1,
.ifs = &desc_iface_full,
},
},
};
/* Bulk-In endpoint */
0x07, /* u8 ep_bLength; */
0x05, /* u8 ep_bDescriptorType; Endpoint */
0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
0x02, /* u8 ep_bmAttributes; Bulk */
0x40, 0x00, /* u16 ep_wMaxPacketSize; */
0x00, /* u8 ep_bInterval; */
static const USBDescIface desc_iface_high = {
.bInterfaceNumber = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
.bInterfaceSubClass = 0x06, /* SCSI */
.bInterfaceProtocol = 0x50, /* Bulk */
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_IN | 0x01,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 512,
},{
.bEndpointAddress = USB_DIR_OUT | 0x02,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = 512,
},
}
};
/* Bulk-Out endpoint */
0x07, /* u8 ep_bLength; */
0x05, /* u8 ep_bDescriptorType; Endpoint */
0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */
0x02, /* u8 ep_bmAttributes; Bulk */
0x40, 0x00, /* u16 ep_wMaxPacketSize; */
0x00 /* u8 ep_bInterval; */
static const USBDescDevice desc_device_high = {
.bcdUSB = 0x0200,
.bMaxPacketSize0 = 64,
.bNumConfigurations = 1,
.confs = (USBDescConfig[]) {
{
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = STR_CONFIG_HIGH,
.bmAttributes = 0xc0,
.nif = 1,
.ifs = &desc_iface_high,
},
},
};
static const USBDesc desc = {
.id = {
.idVendor = 0,
.idProduct = 0,
.bcdDevice = 0,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT,
.iSerialNumber = STR_SERIALNUMBER,
},
.full = &desc_device_full,
.high = &desc_device_high,
.str = desc_strings,
};
static void usb_msd_copy_data(MSDState *s)
@ -152,77 +192,93 @@ static void usb_msd_copy_data(MSDState *s)
s->usb_buf += len;
s->scsi_buf += len;
s->data_len -= len;
if (s->scsi_len == 0) {
if (s->mode == USB_MSDM_DATAIN) {
s->scsi_dev->info->read_data(s->scsi_dev, s->tag);
} else if (s->mode == USB_MSDM_DATAOUT) {
s->scsi_dev->info->write_data(s->scsi_dev, s->tag);
}
if (s->scsi_len == 0 || s->data_len == 0) {
scsi_req_continue(s->req);
}
}
static void usb_msd_send_status(MSDState *s)
static void usb_msd_send_status(MSDState *s, USBPacket *p)
{
struct usb_msd_csw csw;
int len;
csw.sig = cpu_to_le32(0x53425355);
csw.tag = cpu_to_le32(s->tag);
csw.residue = s->residue;
csw.status = s->result;
memcpy(s->usb_buf, &csw, 13);
len = MIN(sizeof(csw), p->len);
memcpy(p->data, &csw, len);
}
static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
uint32_t arg)
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, bus->qbus.parent);
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet;
if (tag != s->tag) {
fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", tag);
}
if (reason == SCSI_REASON_DONE) {
DPRINTF("Command complete %d\n", arg);
s->residue = s->data_len;
s->result = arg != 0;
if (s->packet) {
if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
/* A deferred packet with no write data remaining must be
the status read packet. */
usb_msd_send_status(s);
s->mode = USB_MSDM_CBW;
} else {
if (s->data_len) {
s->data_len -= s->usb_len;
if (s->mode == USB_MSDM_DATAIN)
memset(s->usb_buf, 0, s->usb_len);
s->usb_len = 0;
}
if (s->data_len == 0)
s->mode = USB_MSDM_CSW;
}
s->packet = NULL;
usb_packet_complete(p);
} else if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
}
return;
}
s->scsi_len = arg;
s->scsi_buf = s->scsi_dev->info->get_buf(s->scsi_dev, tag);
assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
s->scsi_len = len;
s->scsi_buf = scsi_req_get_buf(req);
if (p) {
usb_msd_copy_data(s);
if (s->usb_len == 0) {
if (s->packet && s->usb_len == 0) {
/* Set s->packet to NULL before calling usb_packet_complete
because annother request may be issued before
because another request may be issued before
usb_packet_complete returns. */
DPRINTF("Packet complete %p\n", p);
s->packet = NULL;
usb_packet_complete(p);
usb_packet_complete(&s->dev, p);
}
}
}
static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet;
DPRINTF("Command complete %d\n", status);
s->residue = s->data_len;
s->result = status != 0;
if (s->packet) {
if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
/* A deferred packet with no write data remaining must be
the status read packet. */
usb_msd_send_status(s, p);
s->mode = USB_MSDM_CBW;
} else {
if (s->data_len) {
s->data_len -= s->usb_len;
if (s->mode == USB_MSDM_DATAIN) {
memset(s->usb_buf, 0, s->usb_len);
}
s->usb_len = 0;
}
if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
}
}
s->packet = NULL;
usb_packet_complete(&s->dev, p);
} else if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
}
scsi_req_unref(req);
s->req = NULL;
}
static void usb_msd_request_cancelled(SCSIRequest *req)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
if (req == s->req) {
scsi_req_unref(s->req);
s->req = NULL;
s->packet = NULL;
s->scsi_len = 0;
}
}
static void usb_msd_handle_reset(USBDevice *dev)
{
MSDState *s = (MSDState *)dev;
@ -231,88 +287,19 @@ static void usb_msd_handle_reset(USBDevice *dev)
s->mode = USB_MSDM_CBW;
}
static int usb_msd_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
MSDState *s = (MSDState *)dev;
int ret = 0;
int ret;
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
}
ret = 0;
switch (request) {
case DeviceRequest | USB_REQ_GET_STATUS:
data[0] = (1 << USB_DEVICE_SELF_POWERED) |
(dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
data[1] = 0x00;
ret = 2;
break;
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
if (value == USB_DEVICE_REMOTE_WAKEUP) {
dev->remote_wakeup = 0;
} else {
goto fail;
}
ret = 0;
break;
case DeviceOutRequest | USB_REQ_SET_FEATURE:
if (value == USB_DEVICE_REMOTE_WAKEUP) {
dev->remote_wakeup = 1;
} else {
goto fail;
}
ret = 0;
break;
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
dev->addr = value;
ret = 0;
break;
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
switch(value >> 8) {
case USB_DT_DEVICE:
memcpy(data, qemu_msd_dev_descriptor,
sizeof(qemu_msd_dev_descriptor));
ret = sizeof(qemu_msd_dev_descriptor);
break;
case USB_DT_CONFIG:
memcpy(data, qemu_msd_config_descriptor,
sizeof(qemu_msd_config_descriptor));
ret = sizeof(qemu_msd_config_descriptor);
break;
case USB_DT_STRING:
switch(value & 0xff) {
case 0:
/* language ids */
data[0] = 4;
data[1] = 3;
data[2] = 0x09;
data[3] = 0x04;
ret = 4;
break;
case 1:
/* vendor description */
ret = set_usb_string(data, "QEMU " QEMU_VERSION);
break;
case 2:
/* product description */
ret = set_usb_string(data, "QEMU USB HARDDRIVE");
break;
case 3:
/* serial number */
ret = set_usb_string(data, "1");
break;
default:
goto fail;
}
break;
default:
goto fail;
}
break;
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
data[0] = 1;
ret = 1;
break;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
ret = 0;
break;
case DeviceRequest | USB_REQ_GET_INTERFACE:
data[0] = 0;
ret = 1;
@ -321,35 +308,32 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value,
ret = 0;
break;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
if (value == 0 && index != 0x81) { /* clear ep halt */
goto fail;
}
ret = 0;
break;
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
ret = 0;
break;
/* Class specific requests. */
case MassStorageReset:
case ClassInterfaceOutRequest | MassStorageReset:
/* Reset state ready for the next CBW. */
s->mode = USB_MSDM_CBW;
ret = 0;
break;
case GetMaxLun:
case ClassInterfaceRequest | GetMaxLun:
data[0] = 0;
ret = 1;
break;
default:
fail:
ret = USB_RET_STALL;
break;
}
return ret;
}
static void usb_msd_cancel_io(USBPacket *p, void *opaque)
static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
{
MSDState *s = opaque;
s->scsi_dev->info->cancel_io(s->scsi_dev, s->tag);
s->packet = NULL;
s->scsi_len = 0;
MSDState *s = DO_UPCAST(MSDState, dev, dev);
scsi_req_cancel(s->req);
}
static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
@ -395,15 +379,13 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
s->tag, cbw.flags, cbw.cmd_len, s->data_len);
s->residue = 0;
s->scsi_dev->info->send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
s->scsi_len = 0;
s->req = scsi_req_new(s->scsi_dev, s->tag, 0, NULL);
scsi_req_enqueue(s->req, cbw.cmd);
/* ??? Should check that USB and SCSI data transfer
directions match. */
if (s->residue == 0) {
if (s->mode == USB_MSDM_DATAIN) {
s->scsi_dev->info->read_data(s->scsi_dev, s->tag);
} else if (s->mode == USB_MSDM_DATAOUT) {
s->scsi_dev->info->write_data(s->scsi_dev, s->tag);
}
if (s->mode != USB_MSDM_CSW && s->residue == 0) {
scsi_req_continue(s->req);
}
ret = len;
break;
@ -426,7 +408,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
}
if (s->usb_len) {
DPRINTF("Deferring packet %p\n", p);
usb_defer_packet(p, usb_msd_cancel_io, s);
s->packet = p;
ret = USB_RET_ASYNC;
} else {
@ -449,7 +430,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
if (s->data_len != 0 || len < 13)
goto fail;
/* Waiting for SCSI write to complete. */
usb_defer_packet(p, usb_msd_cancel_io, s);
s->packet = p;
ret = USB_RET_ASYNC;
break;
@ -460,15 +440,13 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
if (len < 13)
goto fail;
s->usb_len = len;
s->usb_buf = data;
usb_msd_send_status(s);
usb_msd_send_status(s, p);
s->mode = USB_MSDM_CBW;
ret = 13;
break;
case USB_MSDM_DATAIN:
DPRINTF("Data in %d/%d\n", len, s->data_len);
DPRINTF("Data in %d/%d, scsi_len %d\n", len, s->data_len, s->scsi_len);
if (len > s->data_len)
len = s->data_len;
s->usb_buf = data;
@ -485,7 +463,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
}
if (s->usb_len) {
DPRINTF("Deferring packet %p\n", p);
usb_defer_packet(p, usb_msd_cancel_io, s);
s->packet = p;
ret = USB_RET_ASYNC;
} else {
@ -514,36 +491,71 @@ static void usb_msd_password_cb(void *opaque, int err)
MSDState *s = opaque;
if (!err)
usb_device_attach(&s->dev);
else
err = usb_device_attach(&s->dev);
if (err)
qdev_unplug(&s->dev.qdev);
}
static const struct SCSIBusOps usb_msd_scsi_ops = {
.transfer_data = usb_msd_transfer_data,
.complete = usb_msd_command_complete,
.cancel = usb_msd_request_cancelled
};
static int usb_msd_initfn(USBDevice *dev)
{
MSDState *s = DO_UPCAST(MSDState, dev, dev);
BlockDriverState *bs = s->conf.bs;
DriveInfo *dinfo;
if (!s->dinfo || !s->dinfo->bdrv) {
qemu_error("usb-msd: drive property not set\n");
if (!bs) {
error_report("usb-msd: drive property not set");
return -1;
}
s->dev.speed = USB_SPEED_FULL;
scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete);
s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, s->dinfo, 0);
/*
* Hack alert: this pretends to be a block device, but it's really
* a SCSI bus that can serve only a single device, which it
* creates automatically. But first it needs to detach from its
* blockdev, or else scsi_bus_legacy_add_drive() dies when it
* attaches again.
*
* The hack is probably a bad idea.
*/
bdrv_detach(bs, &s->dev.qdev);
s->conf.bs = NULL;
if (!s->serial) {
/* try to fall back to value set with legacy -drive serial=... */
dinfo = drive_get_by_blockdev(bs);
if (*dinfo->serial) {
s->serial = strdup(dinfo->serial);
}
}
if (s->serial) {
usb_desc_set_string(dev, STR_SERIALNUMBER, s->serial);
}
usb_desc_init(dev);
scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, &usb_msd_scsi_ops);
s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
if (!s->scsi_dev) {
return -1;
}
s->bus.qbus.allow_hotplug = 0;
usb_msd_handle_reset(dev);
if (bdrv_key_required(s->dinfo->bdrv)) {
if (s->dev.qdev.hotplugged) {
monitor_read_bdrv_key_start(cur_mon, s->dinfo->bdrv,
usb_msd_password_cb, s);
if (bdrv_key_required(bs)) {
if (cur_mon) {
monitor_read_bdrv_key_start(cur_mon, bs, usb_msd_password_cb, s);
s->dev.auto_attach = 0;
} else {
autostart = 0;
}
}
add_boot_device_path(s->conf.bootindex, &dev->qdev, "/disk@0,0");
return 0;
}
@ -554,13 +566,12 @@ static USBDevice *usb_msd_init(const char *filename)
QemuOpts *opts;
DriveInfo *dinfo;
USBDevice *dev;
int fatal_error;
const char *p1;
char fmt[32];
/* parse -usbdevice disk: syntax into drive opts */
snprintf(id, sizeof(id), "usb%d", nr++);
opts = qemu_opts_create(&qemu_drive_opts, id, 0);
opts = qemu_opts_create(qemu_find_opts("drive"), id, 0);
p1 = strchr(filename, ':');
if (p1++) {
@ -584,7 +595,7 @@ static USBDevice *usb_msd_init(const char *filename)
qemu_opt_set(opts, "if", "none");
/* create host drive */
dinfo = drive_init(opts, NULL, &fatal_error);
dinfo = drive_init(opts, 0);
if (!dinfo) {
qemu_opts_del(opts);
return NULL;
@ -595,7 +606,10 @@ static USBDevice *usb_msd_init(const char *filename)
if (!dev) {
return NULL;
}
qdev_prop_set_drive(&dev->qdev, "drive", dinfo);
if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
qdev_free(&dev->qdev);
return NULL;
}
if (qdev_init(&dev->qdev) < 0)
return NULL;
@ -605,16 +619,22 @@ static USBDevice *usb_msd_init(const char *filename)
static struct USBDeviceInfo msd_info = {
.product_desc = "QEMU USB MSD",
.qdev.name = "usb-storage",
.qdev.fw_name = "storage",
.qdev.size = sizeof(MSDState),
.usb_desc = &desc,
.init = usb_msd_initfn,
.handle_packet = usb_generic_handle_packet,
.cancel_packet = usb_msd_cancel_io,
.handle_attach = usb_desc_attach,
.handle_reset = usb_msd_handle_reset,
.handle_control = usb_msd_handle_control,
.handle_data = usb_msd_handle_data,
.usbdevice_name = "disk",
.usbdevice_init = usb_msd_init,
.qdev.props = (Property[]) {
DEFINE_PROP_DRIVE("drive", MSDState, dinfo),
DEFINE_BLOCK_PROPERTIES(MSDState, conf),
DEFINE_PROP_STRING("serial", MSDState, serial),
DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
DEFINE_PROP_END_OF_LIST(),
},
};

View File

@ -58,38 +58,23 @@ int dprintf(const char *fmt,...)
#endif
}
static int last_level = 0;
/* Update IRQ levels */
static inline void ohci_intr_update(OHCIState *ohci)
{
uint32_t bits = (ohci->intr_status & ohci->intr) & 0x7fffffff;
int level = 0;
if ((ohci->intr & OHCI_INTR_MIE) && (bits!=0)) // && (ohci->ctl & OHCI_CTL_HCFS))
if ((ohci->intr & OHCI_INTR_MIE) &&
(ohci->intr_status & ohci->intr))
level = 1;
if(level && !last_level)
{
/*
static char reasons[1024];
int first=1;
reasons[0]=0;
#define reason_add(p,t) if(bits&(p)) { if(!first) strcat_s(reasons,1024,", "); first=0; strcat_s(reasons,1024,t); }
reason_add(OHCI_INTR_SO,"Scheduling overrun");
reason_add(OHCI_INTR_WD,"HcDoneHead writeback");
reason_add(OHCI_INTR_SF,"Start of frame");
reason_add(OHCI_INTR_RD,"Resume detect");
reason_add(OHCI_INTR_UE,"Unrecoverable error");
reason_add(OHCI_INTR_FNO,"Frame number overflow");
reason_add(OHCI_INTR_RHSC,"Root hub status change");
reason_add(OHCI_INTR_OC,"Ownership change");
*/
if((ohci->ctl & OHCI_CTL_HCFS)==OHCI_USB_OPERATIONAL)
if( (get_clock() - last_cycle) > MIN_IRQ_INTERVAL)
{
if( (get_clock() - last_cycle) > MIN_IRQ_INTERVAL)
{
USBirq(1);
last_cycle = get_clock();
}
//dprintf("usb-ohci: Interrupt Called. Reason(s): %s\n",reasons);
USBirq(1);
last_cycle = get_clock();
}
}
}
@ -102,55 +87,97 @@ static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
}
/* Attach or detach a device on a root hub port. */
static void ohci_attach(USBPort *port1, USBDevice *dev)
static void ohci_attach(USBPort *port1)
{
OHCIState *s = (OHCIState *)port1->opaque;
OHCIState *s = (OHCIState*)port1->opaque;
OHCIPort *port = &s->rhport[port1->index];
uint32_t old_state = port->ctrl;
if (dev) {
if (port->port.dev) {
usb_attach(port1, NULL);
}
/* set connect status */
port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
/* set connect status */
port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
/* update speed */
if (dev->speed == USB_SPEED_LOW)
port->ctrl |= OHCI_PORT_LSDA;
else
port->ctrl &= ~OHCI_PORT_LSDA;
port->port.dev = dev;
/* notify of remote-wakeup */
if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND)
ohci_set_interrupt(s, OHCI_INTR_RD);
/* send the attach message */
usb_send_msg(dev, USB_MSG_ATTACH);
dprintf("usb-ohci: Attached port %d\n", port1->index);
/* update speed */
if (port->port.dev->speed == USB_SPEED_LOW) {
port->ctrl |= OHCI_PORT_LSDA;
} else {
/* set connect status */
if (port->ctrl & OHCI_PORT_CCS) {
port->ctrl &= ~OHCI_PORT_CCS;
port->ctrl |= OHCI_PORT_CSC;
}
/* disable port */
if (port->ctrl & OHCI_PORT_PES) {
port->ctrl &= ~OHCI_PORT_PES;
port->ctrl |= OHCI_PORT_PESC;
}
dev = port->port.dev;
if (dev) {
/* send the detach message */
usb_send_msg(dev, USB_MSG_DETACH);
}
port->port.dev = NULL;
dprintf("usb-ohci: Detached port %d\n", port1->index);
port->ctrl &= ~OHCI_PORT_LSDA;
}
if (old_state != port->ctrl)
/* notify of remote-wakeup */
if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
ohci_set_interrupt(s, OHCI_INTR_RD);
}
dprintf("usb-ohci: Attached port %d\n", port1->index);
if (old_state != port->ctrl) {
ohci_set_interrupt(s, OHCI_INTR_RHSC);
}
}
static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
{
if (ohci->async_td && ohci->usb_packet.owner == dev) {
usb_cancel_packet(&ohci->usb_packet);
ohci->async_td = 0;
}
}
static void ohci_detach(USBPort *port1)
{
OHCIState *s = (OHCIState*)port1->opaque;
OHCIPort *port = &s->rhport[port1->index];
uint32_t old_state = port->ctrl;
ohci_async_cancel_device(s, port1->dev);
/* set connect status */
if (port->ctrl & OHCI_PORT_CCS) {
port->ctrl &= ~OHCI_PORT_CCS;
port->ctrl |= OHCI_PORT_CSC;
}
/* disable port */
if (port->ctrl & OHCI_PORT_PES) {
port->ctrl &= ~OHCI_PORT_PES;
port->ctrl |= OHCI_PORT_PESC;
}
dprintf("usb-ohci: Detached port %d\n", port1->index);
if (old_state != port->ctrl) {
ohci_set_interrupt(s, OHCI_INTR_RHSC);
}
}
static void ohci_wakeup(USBPort *port1)
{
OHCIState *s = (OHCIState*)port1->opaque;
OHCIPort *port = &s->rhport[port1->index];
uint32_t intr = 0;
if (port->ctrl & OHCI_PORT_PSS) {
dprintf("usb-ohci: port %d: wakeup\n", port1->index);
port->ctrl |= OHCI_PORT_PSSC;
port->ctrl &= ~OHCI_PORT_PSS;
intr = OHCI_INTR_RHSC;
}
/* Note that the controller can be suspended even if this port is not */
if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
dprintf("usb-ohci: remote-wakeup: SUSPEND->RESUME\n");
/* This is the one state transition the controller can do by itself */
s->ctl &= ~OHCI_CTL_HCFS;
s->ctl |= OHCI_USB_RESUME;
/* In suspend mode only ResumeDetected is possible, not RHSC:
* see the OHCI spec 5.1.2.3.
*/
intr = OHCI_INTR_RD;
}
ohci_set_interrupt(s, intr);
}
static void ohci_child_detach(USBPort *port1, USBDevice *child)
{
OHCIState *s = (OHCIState*)port1->opaque;
ohci_async_cancel_device(s, child);
}
/* Reset the controller */
@ -193,8 +220,9 @@ static void ohci_reset(void *opaque)
{
port = &ohci->rhport[i];
port->ctrl = 0;
if (port->port.dev)
ohci_attach(&port->port, port->port.dev);
if (port->port.dev) {
usb_attach(&port->port, port->port.dev);
}
}
if (ohci->async_td) {
usb_cancel_packet(&ohci->usb_packet);
@ -212,7 +240,7 @@ static inline int get_dwords(OHCIState *ohci,
addr += ohci->localmem_base;
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
cpu_physical_memory_read(addr, (uint8_t*)buf, sizeof(*buf));
*buf = (*buf);
}
@ -229,7 +257,7 @@ static inline int put_dwords(OHCIState *ohci,
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint32_t tmp = (*buf);
cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
cpu_physical_memory_write(addr, (uint8_t*)&tmp, sizeof(tmp));
}
return 1;
@ -244,7 +272,7 @@ static inline int get_words(OHCIState *ohci,
addr += ohci->localmem_base;
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
cpu_physical_memory_read(addr, (uint8_t*)buf, sizeof(*buf));
*buf = (*buf);
}
@ -261,7 +289,7 @@ static inline int put_words(OHCIState *ohci,
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint16_t tmp = (*buf);
cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
cpu_physical_memory_write(addr, (uint8_t*)&tmp, sizeof(tmp));
}
return 1;
@ -289,8 +317,7 @@ static inline int ohci_read_iso_td(OHCIState *ohci,
static inline int ohci_read_hcca(OHCIState *ohci,
uint32_t addr, struct ohci_hcca *hcca)
{
cpu_physical_memory_rw(addr + ohci->localmem_base,
(uint8_t *)hcca, sizeof(*hcca), 0);
cpu_physical_memory_read(addr + ohci->localmem_base, (uint8_t*)hcca, sizeof(*hcca));
return 1;
}
@ -316,8 +343,7 @@ static inline int ohci_put_iso_td(OHCIState *ohci,
static inline int ohci_put_hcca(OHCIState *ohci,
uint32_t addr, struct ohci_hcca *hcca)
{
cpu_physical_memory_rw(addr + ohci->localmem_base,
(uint8_t *)hcca, sizeof(*hcca), 1);
cpu_physical_memory_write(addr + ohci->localmem_base, (uint8_t*)hcca, sizeof(*hcca));
return 1;
}
@ -362,9 +388,9 @@ static void ohci_copy_iso_td(OHCIState *ohci,
static void ohci_process_lists(OHCIState *ohci, int completion);
static void ohci_async_complete_packet(USBPacket *packet, void *opaque)
static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
{
OHCIState *ohci = (OHCIState *)opaque;
OHCIState *ohci = (OHCIState*)packet->owner->opaque;
#ifdef DEBUG_PACKET
dprintf("Async packet complete\n");
#endif
@ -379,7 +405,9 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
{
int dir;
size_t len = 0;
#ifdef DEBUG_ISOCH
const char *str = NULL;
#endif
int pid;
int ret;
int i;
@ -443,15 +471,21 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
dir = OHCI_BM(ed->flags, ED_D);
switch (dir) {
case OHCI_TD_DIR_IN:
#ifdef DEBUG_ISOCH
str = "in";
#endif
pid = USB_TOKEN_IN;
break;
case OHCI_TD_DIR_OUT:
#ifdef DEBUG_ISOCH
str = "out";
#endif
pid = USB_TOKEN_OUT;
break;
case OHCI_TD_DIR_SETUP:
#ifdef DEBUG_ISOCH
str = "setup";
#endif
pid = USB_TOKEN_SETUP;
break;
default:
@ -527,9 +561,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
ohci->usb_packet.data = ohci->usb_buf;
ohci->usb_packet.len = len;
ohci->usb_packet.complete_cb = ohci_async_complete_packet;
ohci->usb_packet.complete_opaque = ohci;
ret = dev->info->handle_packet(dev, &ohci->usb_packet);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
}
@ -614,7 +646,9 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
{
int dir;
size_t len = 0;
#ifdef DEBUG_PACKET
const char *str = NULL;
#endif
int pid;
int ret;
int i;
@ -651,15 +685,21 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
switch (dir) {
case OHCI_TD_DIR_IN:
#ifdef DEBUG_PACKET
str = "in";
#endif
pid = USB_TOKEN_IN;
break;
case OHCI_TD_DIR_OUT:
#ifdef DEBUG_PACKET
str = "out";
#endif
pid = USB_TOKEN_OUT;
break;
case OHCI_TD_DIR_SETUP:
#ifdef DEBUG_PACKET
str = "setup";
#endif
pid = USB_TOKEN_SETUP;
break;
default:
@ -681,7 +721,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
flag_r = (td.flags & OHCI_TD_R) != 0;
#ifdef DEBUG_PACKET
dprintf(" TD @ 0x%.8x %" PRId64 " bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
addr, len, str, flag_r, td.cbp, td.be);
addr, (int64_t)len, str, flag_r, td.cbp, td.be);
if (len > 0 && dir != OHCI_TD_DIR_IN) {
dprintf(" data:");
@ -717,9 +757,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
ohci->usb_packet.data = ohci->usb_buf;
ohci->usb_packet.len = len;
ohci->usb_packet.complete_cb = ohci_async_complete_packet;
ohci->usb_packet.complete_opaque = ohci;
ret = dev->info->handle_packet(dev, &ohci->usb_packet);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
}
@ -773,7 +811,6 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
switch (ret) {
case USB_RET_NODEV:
OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING);
return 1;
case USB_RET_NAK:
dprintf("usb-ohci: got NAK\n");
return 1;
@ -873,6 +910,7 @@ static void ohci_sof(OHCIState *ohci)
{
ohci->sof_time = get_clock();
ohci->eof_timer += usb_frame_time;
//ohci->sof_time = qemu_get_clock_ns(vm_clock);
//qemu_mod_timer(ohci->eof_timer, ohci->sof_time + usb_frame_time);
ohci_set_interrupt(ohci, OHCI_INTR_SF);
}
@ -881,9 +919,10 @@ static void ohci_sof(OHCIState *ohci)
static void ohci_process_lists(OHCIState *ohci, int completion)
{
if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head)
dprintf("usb-ohci: head %x, cur %x\n",
ohci->ctrl_head, ohci->ctrl_cur);
if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) {
dprintf("usb-ohci: head %x, cur %x\n",
ohci->ctrl_head, ohci->ctrl_cur);
}
if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) {
ohci->ctrl_cur = 0;
ohci->status &= ~OHCI_STATUS_CLF;
@ -901,7 +940,7 @@ static void ohci_process_lists(OHCIState *ohci, int completion)
/* Do frame processing on frame boundary */
void ohci_frame_boundary(void *opaque)
{
OHCIState *ohci = (OHCIState *)opaque;
OHCIState *ohci = (OHCIState*)opaque;
struct ohci_hcca hcca;
ohci_read_hcca(ohci, ohci->hcca, &hcca);
@ -954,7 +993,7 @@ void ohci_frame_boundary(void *opaque)
/* Start sending SOF tokens across the USB bus, lists are processed in
* next frame
*/
int ohci_bus_start(OHCIState *ohci)
static int ohci_bus_start(OHCIState *ohci)
{
ohci->eof_timer = 0;
@ -966,7 +1005,7 @@ int ohci_bus_start(OHCIState *ohci)
}
/* Stop sending SOF tokens on the bus */
void ohci_bus_stop(OHCIState *ohci)
static void ohci_bus_stop(OHCIState *ohci)
{
if (ohci->eof_timer)
ohci->eof_timer=0;
@ -1072,7 +1111,7 @@ static uint32_t ohci_get_frame_remaining(OHCIState *ohci)
/* Being in USB operational state guarnatees sof_time was
* set already.
*/
tks = get_clock() - ohci->sof_time;
tks = get_clock() - ohci->sof_time;
/* avoid muldiv if possible */
if (tks >= usb_frame_time)
@ -1140,8 +1179,9 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES);
if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS))
if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) {
dprintf("usb-ohci: port %d: SUSPEND\n", portnum);
}
if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) {
dprintf("usb-ohci: port %d: RESET\n", portnum);
@ -1167,9 +1207,11 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
{
OHCIState *ohci = (OHCIState *)ptr;
OHCIState *ohci = (OHCIState*)ptr;
uint32_t retval;
addr &= 0xff;
/* Only aligned reads are allowed on OHCI */
if (addr & 3) {
fprintf(stderr, "usb-ohci: Mis-aligned read\n");
@ -1283,9 +1325,6 @@ uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
}
}
#ifdef TARGET_WORDS_BIGENDIAN
retval = bswap32(retval);
#endif
return retval;
}
@ -1293,9 +1332,7 @@ void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
{
OHCIState *ohci = (OHCIState *)ptr;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
addr &= 0xff;
/* Only aligned reads are allowed on OHCI */
if (addr & 3) {
@ -1344,6 +1381,10 @@ void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
ohci->hcca = val & OHCI_HCCA_MASK;
break;
case 7: /* HcPeriodCurrentED */
/* Ignore writes to this read-only register, Linux does them */
break;
case 8: /* HcControlHeadED */
ohci->ctrl_head = val & OHCI_EDPTR_MASK;
break;
@ -1413,6 +1454,17 @@ void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
}
}
static USBPortOps ohci_port_ops = {
ohci_attach,
ohci_detach,
ohci_child_detach,
ohci_wakeup,
ohci_async_complete_packet,
};
static USBBusOps ohci_bus_ops = {
};
OHCIState *ohci_create(uint32_t base, int ports)
{
OHCIState *ohci=(OHCIState*)malloc(sizeof(OHCIState));
@ -1443,15 +1495,15 @@ OHCIState *ohci_create(uint32_t base, int ports)
usb_bit_time = 1;
}
#endif
dprintf("usb-ohci: usb_bit_time=%" PRId64 " usb_frame_time=%" PRId64 "\n",
usb_frame_time, usb_bit_time);
dprintf("usb-ohci: usb_bit_time=%" PRId64 " usb_frame_time=%" PRId64 "\n",
usb_frame_time, usb_bit_time);
}
ohci->num_ports = ports;
for (i = 0; i < ports; i++) {
ohci->rhport[i].port.opaque = ohci;
ohci->rhport[i].port.index = i;
ohci->rhport[i].port.attach = ohci_attach;
ohci->rhport[i].port.ops = &ohci_port_ops;
}
ohci->async_td = 0;

View File

@ -1,259 +1,382 @@
/*
* QEMU USB API
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-queue.h"
#define USB_TOKEN_SETUP 0x2d
#define USB_TOKEN_IN 0x69 /* device -> host */
#define USB_TOKEN_OUT 0xe1 /* host -> device */
/* specific usb messages, also sent in the 'pid' parameter */
#define USB_MSG_ATTACH 0x100
#define USB_MSG_DETACH 0x101
#define USB_MSG_RESET 0x102
#define USB_RET_NODEV (-1)
#define USB_RET_NAK (-2)
#define USB_RET_STALL (-3)
#define USB_RET_BABBLE (-4)
#define USB_RET_ASYNC (-5)
#define USB_SPEED_LOW 0
#define USB_SPEED_FULL 1
#define USB_SPEED_HIGH 2
#define USB_STATE_NOTATTACHED 0
#define USB_STATE_ATTACHED 1
//#define USB_STATE_POWERED 2
#define USB_STATE_DEFAULT 3
//#define USB_STATE_ADDRESS 4
//#define USB_STATE_CONFIGURED 5
#define USB_STATE_SUSPENDED 6
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PHYSICAL 5
#define USB_CLASS_STILL_IMAGE 6
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_CDC_DATA 0x0a
#define USB_CLASS_CSCID 0x0b
#define USB_CLASS_CONTENT_SEC 0x0d
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
#define USB_TYPE_MASK (0x03 << 5)
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
#define USB_RECIP_MASK 0x1f
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
#define InterfaceRequest \
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
#define InterfaceOutRequest \
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
#define EndpointOutRequest \
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_DEVICE_SELF_POWERED 0
#define USB_DEVICE_REMOTE_WAKEUP 1
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
typedef struct USBBus USBBus;
typedef struct USBPort USBPort;
typedef struct USBDevice USBDevice;
typedef struct USBDeviceInfo USBDeviceInfo;
typedef struct USBPacket USBPacket;
/* definition of a USB device */
struct USBDevice {
//DeviceState qdev;
USBDeviceInfo *info;
void *opaque;
int speed;
uint8_t addr;
char product_desc[32];
int auto_attach;
int attached;
int state;
uint8_t setup_buf[8];
uint8_t data_buf[1024];
int remote_wakeup;
int setup_state;
int setup_len;
int setup_index;
};
struct USBDeviceInfo {
//DeviceInfo qdev;
int (*init)(USBDevice *dev);
/*
* Process USB packet.
* Called by the HC (Host Controller).
*
* Returns length of the transaction
* or one of the USB_RET_XXX codes.
*/
int (*handle_packet)(USBDevice *dev, USBPacket *p);
/*
* Called when device is destroyed.
*/
void (*handle_destroy)(USBDevice *dev);
/*
* Reset the device
*/
void (*handle_reset)(USBDevice *dev);
/*
* Process control request.
* Called from handle_packet().
*
* Returns length or one of the USB_RET_ codes.
*/
int (*handle_control)(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data);
/*
* Process data transfers (both BULK and ISOC).
* Called from handle_packet().
*
* Returns length or one of the USB_RET_ codes.
*/
int (*handle_data)(USBDevice *dev, USBPacket *p);
const char *product_desc;
/* handle legacy -usbdevice command line options */
const char *usbdevice_name;
USBDevice *(*usbdevice_init)(const char *params);
};
typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev);
/* USB port on which a device can be connected */
struct USBPort {
USBDevice *dev;
usb_attachfn attach;
void *opaque;
int index; /* internal port index, may be used with the opaque */
QTAILQ_ENTRY(USBPort) next;
};
typedef void USBCallback(USBPacket * packet, void *opaque);
/* Structure used to hold information about an active USB packet. */
struct USBPacket {
/* Data fields for use by the driver. */
int pid;
uint8_t devaddr;
uint8_t devep;
uint8_t *data;
int len;
/* Internal use by the USB layer. */
USBCallback *complete_cb;
void *complete_opaque;
USBCallback *cancel_cb;
void *cancel_opaque;
};
/* Defer completion of a USB packet. The hadle_packet routine should then
return USB_RET_ASYNC. Packets that complete immediately (before
handle_packet returns) should not call this method. */
static inline void usb_defer_packet(USBPacket *p, USBCallback *cancel,
void * opaque)
{
p->cancel_cb = cancel;
p->cancel_opaque = opaque;
}
/* Notify the controller that an async packet is complete. This should only
be called for packets previously deferred with usb_defer_packet, and
should never be called from within handle_packet. */
static inline void usb_packet_complete(USBPacket *p)
{
p->complete_cb(p, p->complete_opaque);
}
/* Cancel an active packet. The packed must have been deferred with
usb_defer_packet, and not yet completed. */
static inline void usb_cancel_packet(USBPacket * p)
{
p->cancel_cb(p, p->cancel_opaque);
}
void usb_attach(USBPort *port, USBDevice *dev);
int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
int set_usb_string(uint8_t *buf, const char *str);
void usb_send_msg(USBDevice *dev, int msg);
/* usb-hid.c */
void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));
/* usb ports of the VM */
#define VM_USB_HUB_SIZE 2
/* usb-kbd.cpp */
USBDevice *usb_keyboard_init(void);
/*
* QEMU USB API
*
* Copyright (c) 2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-queue.h"
/* Constants related to the USB / PCI interaction */
#define USB_SBRN 0x60 /* Serial Bus Release Number Register */
#define USB_RELEASE_1 0x10 /* USB 1.0 */
#define USB_RELEASE_2 0x20 /* USB 2.0 */
#define USB_RELEASE_3 0x30 /* USB 3.0 */
#define USB_TOKEN_SETUP 0x2d
#define USB_TOKEN_IN 0x69 /* device -> host */
#define USB_TOKEN_OUT 0xe1 /* host -> device */
/* specific usb messages, also sent in the 'pid' parameter */
#define USB_MSG_ATTACH 0x100
#define USB_MSG_DETACH 0x101
#define USB_MSG_RESET 0x102
#define USB_RET_NODEV (-1)
#define USB_RET_NAK (-2)
#define USB_RET_STALL (-3)
#define USB_RET_BABBLE (-4)
#define USB_RET_ASYNC (-5)
#define USB_SPEED_LOW 0
#define USB_SPEED_FULL 1
#define USB_SPEED_HIGH 2
#define USB_SPEED_SUPER 3
#define USB_SPEED_MASK_LOW (1 << USB_SPEED_LOW)
#define USB_SPEED_MASK_FULL (1 << USB_SPEED_FULL)
#define USB_SPEED_MASK_HIGH (1 << USB_SPEED_HIGH)
#define USB_SPEED_MASK_SUPER (1 << USB_SPEED_SUPER)
#define USB_STATE_NOTATTACHED 0
#define USB_STATE_ATTACHED 1
//#define USB_STATE_POWERED 2
#define USB_STATE_DEFAULT 3
//#define USB_STATE_ADDRESS 4
//#define USB_STATE_CONFIGURED 5
#define USB_STATE_SUSPENDED 6
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PHYSICAL 5
#define USB_CLASS_STILL_IMAGE 6
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_CDC_DATA 0x0a
#define USB_CLASS_CSCID 0x0b
#define USB_CLASS_CONTENT_SEC 0x0d
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
#define USB_TYPE_MASK (0x03 << 5)
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
#define USB_RECIP_MASK 0x1f
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
#define InterfaceRequest \
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
#define InterfaceOutRequest \
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
#define EndpointOutRequest \
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
#define ClassInterfaceRequest \
((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
#define ClassInterfaceOutRequest \
((USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_DEVICE_SELF_POWERED 0
#define USB_DEVICE_REMOTE_WAKEUP 1
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_DT_DEVICE_QUALIFIER 0x06
#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_DT_DEBUG 0x0A
#define USB_DT_INTERFACE_ASSOC 0x0B
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
typedef struct USBBus USBBus;
typedef struct USBBusOps USBBusOps;
typedef struct USBPort USBPort;
typedef struct USBDevice USBDevice;
typedef struct USBDeviceInfo USBDeviceInfo;
typedef struct USBPacket USBPacket;
typedef struct USBDesc USBDesc;
typedef struct USBDescID USBDescID;
typedef struct USBDescDevice USBDescDevice;
typedef struct USBDescConfig USBDescConfig;
typedef struct USBDescIfaceAssoc USBDescIfaceAssoc;
typedef struct USBDescIface USBDescIface;
typedef struct USBDescEndpoint USBDescEndpoint;
typedef struct USBDescOther USBDescOther;
typedef struct USBDescString USBDescString;
struct USBDescString {
uint8_t index;
char *str;
QLIST_ENTRY(USBDescString) next;
};
/* definition of a USB device */
struct USBDevice {
//DeviceState qdev;
USBDeviceInfo *info;
USBPort *port;
char *port_path;
void *opaque;
/* Actual connected speed */
int speed;
/* Supported speeds, not in info because it may be variable (hostdevs) */
int speedmask;
uint8_t addr;
char product_desc[32];
int auto_attach;
int attached;
int32_t state;
uint8_t setup_buf[8];
uint8_t data_buf[4096];
int32_t remote_wakeup;
int32_t setup_state;
int32_t setup_len;
int32_t setup_index;
QLIST_HEAD(, USBDescString) strings;
const USBDescDevice *device;
const USBDescConfig *config;
};
struct USBDeviceInfo {
//DeviceInfo qdev;
int (*init)(USBDevice *dev);
/*
* Process USB packet.
* Called by the HC (Host Controller).
*
* Returns length of the transaction
* or one of the USB_RET_XXX codes.
*/
int (*handle_packet)(USBDevice *dev, USBPacket *p);
/*
* Called when a packet is canceled.
*/
void (*cancel_packet)(USBDevice *dev, USBPacket *p);
/*
* Called when device is destroyed.
*/
void (*handle_destroy)(USBDevice *dev);
/*
* Attach the device
*/
void (*handle_attach)(USBDevice *dev);
/*
* Reset the device
*/
void (*handle_reset)(USBDevice *dev);
/*
* Process control request.
* Called from handle_packet().
*
* Returns length or one of the USB_RET_ codes.
*/
int (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
int index, int length, uint8_t *data);
/*
* Process data transfers (both BULK and ISOC).
* Called from handle_packet().
*
* Returns length or one of the USB_RET_ codes.
*/
int (*handle_data)(USBDevice *dev, USBPacket *p);
const char *product_desc;
const USBDesc *usb_desc;
/* handle legacy -usbdevice command line options */
const char *usbdevice_name;
USBDevice *(*usbdevice_init)(const char *params);
};
typedef struct USBPortOps {
void (*attach)(USBPort *port);
void (*detach)(USBPort *port);
/*
* This gets called when a device downstream from the device attached to
* the port (iow attached through a hub) gets detached.
*/
void (*child_detach)(USBPort *port, USBDevice *child);
void (*wakeup)(USBPort *port);
/*
* Note that port->dev will be different then the device from which
* the packet originated when a hub is involved, if you want the orginating
* device use p->owner
*/
void (*complete)(USBPort *port, USBPacket *p);
} USBPortOps;
/* USB port on which a device can be connected */
struct USBPort {
USBDevice *dev;
int speedmask;
char path[16];
USBPortOps *ops;
void *opaque;
int index; /* internal port index, may be used with the opaque */
QTAILQ_ENTRY(USBPort) next;
};
typedef void USBCallback(USBPacket * packet, void *opaque);
/* Structure used to hold information about an active USB packet. */
struct USBPacket {
/* Data fields for use by the driver. */
int pid;
uint8_t devaddr;
uint8_t devep;
uint8_t *data;
int len;
/* Internal use by the USB layer. */
USBDevice *owner;
};
int usb_handle_packet(USBDevice *dev, USBPacket *p);
void usb_packet_complete(USBDevice *dev, USBPacket *p);
void usb_cancel_packet(USBPacket * p);
void usb_attach(USBPort *port, USBDevice *dev);
void usb_wakeup(USBDevice *dev);
int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
int set_usb_string(uint8_t *buf, const char *str);
void usb_send_msg(USBDevice *dev, int msg);
/* usb-linux.c */
//USBDevice *usb_host_device_open(const char *devname);
//int usb_host_device_close(const char *devname);
//void usb_host_info(Monitor *mon);
/* usb-hid.c */
void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *));
/* usb-bt.c */
//USBDevice *usb_bt_init(HCIInfo *hci);
/* usb ports of the VM */
#define VM_USB_HUB_SIZE 8
/* usb-musb.c */
enum musb_irq_source_e {
musb_irq_suspend = 0,
musb_irq_resume,
musb_irq_rst_babble,
musb_irq_sof,
musb_irq_connect,
musb_irq_disconnect,
musb_irq_vbus_request,
musb_irq_vbus_error,
musb_irq_rx,
musb_irq_tx,
musb_set_vbus,
musb_set_session,
__musb_irq_max,
};
typedef struct MUSBState MUSBState;
//MUSBState *musb_init(qemu_irq *irqs);
uint32_t musb_core_intr_get(MUSBState *s);
void musb_core_intr_clear(MUSBState *s, uint32_t mask);
void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
/* usb-bus.c */
struct USBBus {
//BusState qbus;
USBBusOps *ops;
int busnr;
int nfree;
int nused;
QTAILQ_HEAD(, USBPort) free;
QTAILQ_HEAD(, USBPort) used;
QTAILQ_ENTRY(USBBus) next;
};
struct USBBusOps {
int (*register_companion)(USBBus *bus, USBPort *ports[],
uint32_t portcount, uint32_t firstport);
};
//void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
USBBus *usb_bus_find(int busnr);
void usb_qdev_register(USBDeviceInfo *info);
void usb_qdev_register_many(USBDeviceInfo *info);
USBDevice *usb_create(USBBus *bus, const char *name);
USBDevice *usb_create_simple(USBBus *bus, const char *name);
USBDevice *usbdevice_create(const char *cmdline);
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
USBPortOps *ops, int speedmask);
int usb_register_companion(const char *masterbus, USBPort *ports[],
uint32_t portcount, uint32_t firstport,
void *opaque, USBPortOps *ops, int speedmask);
void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
void usb_unregister_port(USBBus *bus, USBPort *port);
int usb_device_attach(USBDevice *dev);
int usb_device_detach(USBDevice *dev);
int usb_device_delete_addr(int busnr, int addr);
//
//static inline USBBus *usb_bus_from_device(USBDevice *d)
//{
// return DO_UPCAST(USBBus, qbus, d->qdev.parent_bus);
//}
USBDevice *usb_keyboard_init(void);

View File

@ -6,17 +6,6 @@
void cpu_physical_memory_rw(uint32_t addr, uint8_t *buf,
int len, int is_write);
static inline void cpu_physical_memory_read(uint32_t addr,
uint8_t *buf, int len)
{
cpu_physical_memory_rw(addr, buf, len, 0);
}
static inline void cpu_physical_memory_write(uint32_t addr,
const uint8_t *buf, int len)
{
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
}
/* compute with 96 bit intermediate result: (a*b)/c */
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
{

View File

@ -95,8 +95,16 @@ static inline char *realpath(const char *path, char *resolved_path)
/* vl.c */
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c);
void cpu_physical_memory_rw(uint32_t addr, uint8_t *buf, int len, int is_write);
static inline void cpu_physical_memory_read(uint32_t addr, uint8_t *buf, int len);
static inline void cpu_physical_memory_write(uint32_t addr, const uint8_t *buf, int len);
static inline void cpu_physical_memory_read(uint32_t addr, uint8_t *buf, int len)
{
cpu_physical_memory_rw(addr, buf, len, 0);
}
static inline void cpu_physical_memory_write(uint32_t addr, const uint8_t *buf, int len)
{
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
}
void *qemu_mallocz(uint32_t size);
#endif /* VL_H */