- USB MSD support moved to separate files and C++ object

* partial rewrite of the USB device emulation code (TODO: mouse and keypad)
  * configure.in and iodev makefile updates
  * removed old-style data structure for the USB harddisk
  * TODO: save/restore support for removable devices
- PCI USB destructor now resets all runtime parameter handlers
- set log prefix for the SCSI device
- fixed a warning in the SCSI emulation code
This commit is contained in:
Volker Ruppert 2007-03-18 11:17:28 +00:00
parent e39769a7e8
commit a70cc33578
9 changed files with 1073 additions and 584 deletions

View File

@ -2,7 +2,7 @@ dnl // Process this file with autoconf to produce a configure script.
AC_PREREQ(2.50)
AC_INIT(bochs.h)
AC_REVISION([[$Id: configure.in,v 1.332 2007-01-25 19:09:36 sshwarts Exp $]])
AC_REVISION([[$Id: configure.in,v 1.333 2007-03-18 11:17:27 vruppert Exp $]])
AC_CONFIG_HEADER(config.h)
AC_CONFIG_HEADER(ltdlconf.h)
@ -772,6 +772,8 @@ AC_ARG_ENABLE(pcidev,
]
)
USBDEV_OBJS=''
SCSI_OBJS=''
AC_MSG_CHECKING(for limited USB support)
AC_ARG_ENABLE(usb,
[ --enable-usb enable limited USB support],
@ -779,6 +781,8 @@ AC_ARG_ENABLE(usb,
AC_MSG_RESULT(yes)
AC_DEFINE(BX_SUPPORT_PCIUSB, 1)
PCI_OBJ="$PCI_OBJ pciusb.o"
USBDEV_OBJS="usb_msd.o"
SCSI_OBJS="scsi_device.o"
else
AC_MSG_RESULT(no)
AC_DEFINE(BX_SUPPORT_PCIUSB, 0)
@ -789,6 +793,9 @@ AC_ARG_ENABLE(usb,
]
)
AC_SUBST(USBDEV_OBJS)
AC_SUBST(SCSI_OBJS)
AC_MSG_CHECKING(for PCI pseudo NIC support)
AC_ARG_ENABLE(pnic,
[ --enable-pnic enable PCI pseudo NIC support],

View File

@ -58,6 +58,8 @@ CDROM_OBJS = @CDROM_OBJS@
IOAPIC_OBJS = @IOAPIC_OBJS@
SOUNDLOW_OBJS = @SOUNDLOW_OBJS@
NETLOW_OBJS = @NETLOW_OBJS@
USBDEV_OBJS = @USBDEV_OBJS@
SCSI_OBJS = @SCSI_OBJS@
BX_INCDIRS = -I.. -I$(srcdir)/.. -I../@INSTRUMENT_DIR@ -I$(srcdir)/../@INSTRUMENT_DIR@
LOCAL_CXXFLAGS = $(MCH_CFLAGS)
@ -100,10 +102,11 @@ OBJS_THAT_SUPPORT_OTHER_PLUGINS = \
hdimage.o \
vmware3.o \
vmware4.o \
scsi_device.o \
$(CDROM_OBJS) \
$(SOUNDLOW_OBJS) \
$(NETLOW_OBJS)
$(NETLOW_OBJS) \
$(USBDEV_OBJS) \
$(SCSI_OBJS)
NONPLUGIN_OBJS = @IODEV_NON_PLUGIN_OBJS@
PLUGIN_OBJS = @IODEV_PLUGIN_OBJS@
@ -159,8 +162,8 @@ libbx_serial.la: serial.lo serial_raw.lo
libbx_vga.la: vga.lo svga_cirrus.lo
$(LIBTOOL) --mode=link $(CXX) -module vga.lo svga_cirrus.lo -o libbx_vga.la -rpath $(PLUGIN_PATH)
libbx_pciusb.la: pciusb.lo scsi_device.lo hdimage.lo
$(LIBTOOL) --mode=link $(CXX) -module pciusb.lo scsi_device.lo hdimage.lo -o libbx_pciusb.la -rpath $(PLUGIN_PATH)
libbx_pciusb.la: pciusb.lo usb_msd.lo scsi_device.lo hdimage.lo
$(LIBTOOL) --mode=link $(CXX) -module pciusb.lo usb_msd.lo scsi_device.lo hdimage.lo -o libbx_pciusb.la -rpath $(PLUGIN_PATH)
#### building DLLs for win32 (tested on cygwin only)
bx_%.dll: %.o
@ -194,8 +197,8 @@ bx_serial.dll: serial.o serial_raw.o
bx_vga.dll: vga.o svga_cirrus.o
$(CXX) $(CXXFLAGS) -shared -o bx_vga.dll vga.o svga_cirrus.o $(WIN32_DLL_IMPORT_LIBRARY)
bx_pciusb.dll: pciusb.o scsi_device.o hdimage.o
$(CXX) $(CXXFLAGS) -shared -o bx_pciusb.dll pciusb.o scsi_device.o hdimage.o $(WIN32_DLL_IMPORT_LIBRARY)
bx_pciusb.dll: pciusb.o usb_msd.o scsi_device.o hdimage.o
$(CXX) $(CXXFLAGS) -shared -o bx_pciusb.dll pciusb.o usb_msd.o scsi_device.o hdimage.o $(WIN32_DLL_IMPORT_LIBRARY)
##### end DLL section

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: pciusb.cc,v 1.49 2007-03-16 18:23:13 vruppert Exp $
// $Id: pciusb.cc,v 1.50 2007-03-18 11:17:28 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004 MandrakeSoft S.A.
@ -59,8 +59,7 @@
#include "iodev.h"
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB
#include "hdimage.h"
#include "scsi_device.h"
#include "usb_msd.h"
#define LOG_THIS theUSBDevice->
@ -69,6 +68,45 @@ bx_pciusb_c* theUSBDevice = NULL;
const Bit8u usb_iomask[32] = {2, 1, 2, 1, 2, 1, 2, 0, 4, 0, 0, 0, 1, 0, 0, 0,
3, 1, 3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// Dumps the contents of a buffer to the log file
void usb_dump_packet(Bit8u *data, unsigned size)
{
char the_packet[256], str[16];
strcpy(the_packet, "Packet contents (in hex):");
unsigned offset = 0;
for (unsigned p=0; p<size; p++) {
if (!(p & 0x0F)) {
BX_DEBUG(("%s", the_packet));
sprintf(the_packet, " 0x%04X ", offset);
offset += 16;
}
sprintf(str, " %02X", data[p]);
strcat(the_packet, str);
}
if (strlen(the_packet))
BX_DEBUG(("%s", the_packet));
}
int set_usb_string(Bit8u *buf, const char *str)
{
int len, i;
Bit8u *q;
q = buf;
len = strlen(str);
if (len > 32) {
*q = 0;
return 0;
}
*q++ = 2 * len + 2;
*q++ = 3;
for(i = 0; i < len; i++) {
*q++ = str[i];
*q++ = 0;
}
return q - buf;
}
int libpciusb_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
theUSBDevice = new bx_pciusb_c();
@ -91,22 +129,21 @@ bx_pciusb_c::bx_pciusb_c()
bx_pciusb_c::~bx_pciusb_c()
{
MSDState *s;
if (BX_USB_THIS device_buffer != NULL)
delete [] BX_USB_THIS device_buffer;
for (int i=0; i<USB_CUR_DEVS; i++) {
if (BX_USB_THIS hub[0].device[i].dev_type == USB_DEV_TYPE_DISK) {
s = (MSDState*)BX_USB_THIS hub[0].device[i].devstate;
if (s != NULL) {
usb_msd_handle_destroy(s);
for (int i=0; i<BX_USB_CONFDEV; i++) {
for (int j=0; j<USB_NUM_PORTS; j++) {
if (BX_USB_THIS hub[i].usb_port[j].device != NULL) {
delete BX_USB_THIS hub[i].usb_port[j].device;
}
}
}
SIM->get_param_string(BXPN_USB1_PORT1)->set_handler(NULL);
SIM->get_param_string(BXPN_USB1_OPTION1)->set_handler(NULL);
SIM->get_param_string(BXPN_USB1_PORT2)->set_handler(NULL);
SIM->get_param_string(BXPN_USB1_OPTION2)->set_handler(NULL);
BX_DEBUG(("Exit"));
}
@ -237,6 +274,10 @@ void bx_pciusb_c::reset(unsigned type)
BX_USB_THIS hub[i].usb_port[j].able_changed = 0;
BX_USB_THIS hub[i].usb_port[j].status = 0;
BX_USB_THIS hub[i].usb_port[j].device_num = -1;
if (BX_USB_THIS hub[i].usb_port[j].device != NULL) {
delete BX_USB_THIS hub[i].usb_port[j].device;
BX_USB_THIS hub[i].usb_port[j].device = NULL;
}
}
}
@ -248,7 +289,6 @@ void bx_pciusb_c::reset(unsigned type)
BX_USB_THIS keyboard_connected = 0;
BX_USB_THIS mouse_connected = 0;
BX_USB_THIS disk_connected = 0;
// include the device(s) initialize code
#include "pciusb_devs.h"
@ -367,7 +407,7 @@ void bx_pciusb_c::init_device(Bit8u port, const char *devname)
} else if (!strcmp(devname, "disk")) {
type = USB_DEV_TYPE_DISK;
connected = 1;
BX_USB_THIS disk_connected = 1;
BX_USB_THIS hub[0].usb_port[port].device = new usb_msd_device_t();
} else {
BX_PANIC(("unknown USB device: %s", devname));
return;
@ -522,9 +562,14 @@ void bx_pciusb_c::write(Bit32u address, Bit32u value, unsigned io_len)
if (BX_USB_THIS hub[0].usb_command.host_reset) {
BX_USB_THIS reset(0);
for (unsigned i=0; i<USB_NUM_PORTS; i++) {
if (BX_USB_THIS hub[0].usb_port[i].status)
usb_set_connect_status(i, BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[i].device_num].dev_type,
BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[i].device_num].connect_status);
if (BX_USB_THIS hub[0].usb_port[i].status) {
if (BX_USB_THIS hub[0].usb_port[i].device != NULL) {
BX_USB_THIS usb_send_msg(BX_USB_THIS hub[0].usb_port[i].device, USB_MSG_RESET);
} else {
usb_set_connect_status(i, BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[i].device_num].dev_type,
BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[i].device_num].connect_status);
}
}
BX_USB_THIS hub[0].usb_port[i].connect_changed = 1;
BX_USB_THIS hub[0].usb_port[i].enabled = 0;
BX_USB_THIS hub[0].usb_port[i].able_changed = 1;
@ -660,8 +705,15 @@ void bx_pciusb_c::write(Bit32u address, Bit32u value, unsigned io_len)
BX_USB_THIS hub[0].usb_port[port].enabled = 0;
// are we are currently connected/disconnected
if (BX_USB_THIS hub[0].usb_port[port].status) {
BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[port].device_num].connect_status = 0;
usb_set_connect_status(port, BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[port].device_num].dev_type, 1);
if (BX_USB_THIS hub[0].usb_port[port].device != NULL) {
BX_USB_THIS hub[0].usb_port[port].low_speed =
(BX_USB_THIS hub[0].usb_port[port].device->get_speed() == USB_SPEED_LOW);
usb_set_connect_status(port, BX_USB_THIS hub[0].usb_port[port].device->get_type(), 1);
BX_USB_THIS usb_send_msg(BX_USB_THIS hub[0].usb_port[port].device, USB_MSG_RESET);
} else {
BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[port].device_num].connect_status = 0;
usb_set_connect_status(port, BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[port].device_num].dev_type, 1);
}
}
BX_INFO(("Port%d: Reset", port+1));
}
@ -853,9 +905,10 @@ void bx_pciusb_c::usb_timer(void)
bx_bool bx_pciusb_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *td) {
int i, j, len;
int i, j, len = 0, ret = 0;
Bit8u protocol = 0;
bx_bool fnd;
usb_device_t *newdev = NULL;
Bit16u maxlen = (td->dword2 >> 21);
Bit8u addr = (td->dword2 >> 8) & 0x7F;
@ -893,11 +946,22 @@ bx_bool bx_pciusb_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *td)
break;
}
}
for (i=0; i<USB_NUM_PORTS; i++) {
if (BX_USB_THIS hub[0].usb_port[i].device != NULL) {
if (BX_USB_THIS hub[0].usb_port[i].device->get_connected()) {
at_least_one = 1;
if (BX_USB_THIS hub[0].usb_port[i].device->get_address() == addr) {
newdev = BX_USB_THIS hub[0].usb_port[i].device;
break;
}
}
}
}
if (!at_least_one) {
BX_USB_THIS set_status(td, 1, 0, 0, 0, (pid==USB_TOKEN_SETUP)?1:0, 0, 0x007); // an 8 byte packet was received, but stalled
return 1;
}
if (dev == NULL) {
if ((dev == NULL) && (newdev == NULL)) {
if ((pid == USB_TOKEN_OUT) && (maxlen == 0x7FF) && (addr == 0)) {
// This is the "keep awake" packet that Windows sends once a schedule cycle.
// For now, let it pass through to the code below.
@ -915,6 +979,48 @@ bx_bool bx_pciusb_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *td)
maxlen++;
maxlen &= 0x7FF;
if (newdev != NULL) {
BX_USB_THIS usb_packet.pid = pid;
BX_USB_THIS usb_packet.devaddr = addr;
BX_USB_THIS usb_packet.devep = endpt;
BX_USB_THIS usb_packet.data = device_buffer;
BX_USB_THIS usb_packet.len = maxlen;
switch (pid) {
case USB_TOKEN_OUT:
case USB_TOKEN_SETUP:
if (maxlen > 0) {
DEV_MEM_READ_PHYSICAL(td->dword3, maxlen, device_buffer);
}
ret = newdev->handle_packet(&BX_USB_THIS usb_packet);
len = maxlen;
break;
case USB_TOKEN_IN:
ret = newdev->handle_packet(&BX_USB_THIS usb_packet);
if (ret >= 0) {
len = ret;
if (len > maxlen) {
len = maxlen;
ret = USB_RET_BABBLE;
}
if (len > 0) {
DEV_MEM_WRITE_PHYSICAL(td->dword3, len, device_buffer);
}
} else {
len = 0;
}
break;
default:
BX_USB_THIS hub[i].usb_status.host_error = 1;
BX_USB_THIS set_irq_level(1);
}
if (ret >= 0) {
BX_USB_THIS set_status(td, 0, 0, 0, 0, 0, 0, len-1);
} else {
BX_USB_THIS set_status(td, 1, 0, 0, 0, 0, 0, 0x007); // stalled
}
return 1;
}
if (dev) {
if (maxlen > dev->function.device_descr.max_packet_size)
maxlen = dev->function.device_descr.max_packet_size;
@ -965,21 +1071,6 @@ bx_bool bx_pciusb_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *td)
BX_USB_THIS set_status(td, 0, 0, 0, 0, 0, 0, cnt-1);
break;
case 0x50: // USB Mass Storage
BX_USB_THIS usb_packet.pid = pid;
BX_USB_THIS usb_packet.devaddr = addr;
BX_USB_THIS usb_packet.devep = endpt;
BX_USB_THIS usb_packet.data = device_buffer;
BX_USB_THIS usb_packet.len = cnt;
len = usb_msd_handle_data((MSDState*)dev->devstate, &BX_USB_THIS usb_packet);
if (len >= 0) {
DEV_MEM_WRITE_PHYSICAL(td->dword3, len, device_buffer);
BX_USB_THIS set_status(td, 0, 0, 0, 0, 0, 0, len-1);
} else {
BX_USB_THIS set_status(td, 1, 0, 0, 0, 0, 0, cnt-1);
}
break;
default:
BX_PANIC(("Unknown/unsupported endpt protocol issued an Interrupt In / Bulk packet. protocol %i", protocol));
}
@ -1013,7 +1104,7 @@ bx_bool bx_pciusb_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *td)
bx_gui->statusbar_setitem(BX_USB_THIS hub[0].statusbar_id[0], 1);
cnt = (dev->function.in_cnt < maxlen) ? dev->function.in_cnt : maxlen;
DEV_MEM_WRITE_PHYSICAL(td->dword3, cnt, dev->function.in);
dump_packet(dev->function.in, cnt);
usb_dump_packet(dev->function.in, cnt);
dev->function.in += cnt;
dev->function.in_cnt -= cnt;
BX_USB_THIS set_status(td, 0, 0, 0, 0, 0, 0, cnt-1);
@ -1050,20 +1141,6 @@ bx_bool bx_pciusb_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *td)
BX_PANIC(("Mouse received and OUT packet!"));
break;
case 0x50: // USB Mass Storage
BX_USB_THIS usb_packet.pid = pid;
BX_USB_THIS usb_packet.devaddr = addr;
BX_USB_THIS usb_packet.devep = endpt;
BX_USB_THIS usb_packet.data = bulk_int_packet;
BX_USB_THIS usb_packet.len = maxlen;
len = usb_msd_handle_data((MSDState*)dev->devstate, &BX_USB_THIS usb_packet);
if (len >= 0) {
BX_USB_THIS set_status(td, 0, 0, 0, 0, 0, 0, maxlen-1);
} else {
BX_USB_THIS set_status(td, 1, 0, 0, 0, 0, 0, maxlen-1);
}
break;
default:
BX_PANIC(("Unknown/unsupported endpt protocol issued an Interrupt Out / Bulk packet. protocol %i", protocol));
}
@ -1370,22 +1447,6 @@ bx_bool bx_pciusb_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *td)
BX_USB_THIS set_status(td, 0, 0, 0, 0, 0, 0, 0x007); // an 8 byte packet was received
}
break;
case 0xFE:
// FIXME: protocol type should be checked
BX_INFO(("Request: get max. LUN"));
*device_buffer = 0;
dev->function.in = device_buffer;
dev->function.in_cnt = 1;
BX_USB_THIS set_status(td, 0, 0, 0, 0, 0, 0, 0x007); // an 8 byte packet was received
break;
case 0xFF:
// FIXME: protocol type should be checked
BX_INFO(("Request: mass storage reset"));
if (dev->devstate != NULL) {
((MSDState*)dev->devstate)->mode = USB_MSDM_CBW;
}
BX_USB_THIS set_status(td, 0, 0, 0, 0, 0, 0, 0x007); // an 8 byte packet was received
break;
default:
BX_PANIC((" **** illegal or unknown REQUEST sent to Host Controller: %02x", data[1]));
}
@ -1409,12 +1470,12 @@ unsigned bx_pciusb_c::GetDescriptor(struct USB_DEVICE *dev, struct REQUEST_PACKE
packet->request, packet->request_type, packet->value, packet->length, packet->index));
switch (packet->value >> 8) {
case DEVICE:
case USB_DT_DEVICE:
dev->function.in = (Bit8u *) &dev->function.device_descr;
dev->function.in_cnt = dev->function.device_descr.len;
ret = 0;
break;
case CONFIG:
case USB_DT_CONFIG:
memcpy(p, &dev->function.device_config[dev->config], 9); p += 9; // config descriptor
for (i=0; i<dev->function.device_config[dev->config].interfaces; i++) {
memcpy(p, &dev->function.device_config[dev->config].Interface[i], 9); p += 9;
@ -1430,7 +1491,7 @@ unsigned bx_pciusb_c::GetDescriptor(struct USB_DEVICE *dev, struct REQUEST_PACKE
dev->function.in_cnt = (p - device_buffer);
ret = 0;
break;
case STRING:
case USB_DT_STRING:
switch (packet->value & 0xFF) {
case 0: // string descriptor table
dev->function.in = (Bit8u *) &dev->function.str_descriptor;
@ -1448,17 +1509,17 @@ unsigned bx_pciusb_c::GetDescriptor(struct USB_DEVICE *dev, struct REQUEST_PACKE
ret = 1;
}
break;
case INTERFACE:
case USB_DT_INTERFACE:
BX_PANIC(("GET_DESCRIPTOR: INTERFACE not implemented yet."));
ret = 1;
break;
case ENDPOINT:
case USB_DT_ENDPOINT:
BX_PANIC(("GET_DESCRIPTOR: ENDPOINT not implemented yet."));
ret = 1;
break;
case DEVICE_QUALIFIER:
case USB_DT_DEVICE_QUALIFIER:
device_buffer[0] = 10;
device_buffer[1] = DEVICE_QUALIFIER;
device_buffer[1] = USB_DT_DEVICE_QUALIFIER;
memcpy(device_buffer+2, &dev->function.device_descr+2, 6);
device_buffer[8] = 1;
device_buffer[9] = 0;
@ -1466,11 +1527,11 @@ unsigned bx_pciusb_c::GetDescriptor(struct USB_DEVICE *dev, struct REQUEST_PACKE
dev->function.in_cnt = 10;
ret = 0;
break;
case OTHER_SPEED_CONFIG:
case USB_DT_OTHER_SPEED_CONFIG:
BX_PANIC(("GET_DESCRIPTOR: OTHER_SPEED_CONFIG not implemented yet."));
ret = 1;
break;
case INTERFACE_POWER:
case USB_DT_INTERFACE_POWER:
BX_PANIC(("GET_DESCRIPTOR: INTERFACE_POWER not implemented yet."));
ret = 1;
break;
@ -1676,9 +1737,70 @@ void bx_pciusb_c::usb_mouse_enabled_changed(bx_bool enable)
void bx_pciusb_c::usb_set_connect_status(Bit8u port, int type, bx_bool connected)
{
MSDState *s;
char pname[BX_PATHNAME_LEN];
if (BX_USB_THIS hub[0].usb_port[port].device != NULL) {
if (BX_USB_THIS hub[0].usb_port[port].device->get_type() == type) {
if (connected) {
if (!BX_USB_THIS hub[0].usb_port[port].device->get_connected()) {
BX_USB_THIS hub[0].usb_port[port].low_speed =
(BX_USB_THIS hub[0].usb_port[port].device->get_speed() == USB_SPEED_LOW);
}
if (BX_USB_THIS hub[0].usb_port[port].low_speed) {
BX_USB_THIS hub[0].usb_port[port].line_dminus = 1; // dminus=1 & dplus=0 = low speed (at idle time)
BX_USB_THIS hub[0].usb_port[port].line_dplus = 0; // dminus=0 & dplus=1 = high speed (at idle time)
} else {
BX_USB_THIS hub[0].usb_port[port].line_dminus = 0; // dminus=1 & dplus=0 = low speed (at idle time)
BX_USB_THIS hub[0].usb_port[port].line_dplus = 1; // dminus=0 & dplus=1 = high speed (at idle time)
}
BX_USB_THIS hub[0].usb_port[port].status = 1; //
BX_USB_THIS hub[0].usb_port[port].connect_changed = 1;
BX_USB_THIS hub[0].usb_port[port].able_changed = 1;
// if in suspend state, signal resume
if (BX_USB_THIS hub[0].usb_command.suspend) {
BX_USB_THIS hub[0].usb_port[port].resume = 1;
BX_USB_THIS hub[0].usb_status.resume = 1;
if (BX_USB_THIS hub[0].usb_enable.resume) {
BX_USB_THIS hub[0].usb_status.interrupt = 1;
set_irq_level(1);
}
}
if ((type == USB_DEV_TYPE_DISK) &&
(!BX_USB_THIS hub[0].usb_port[port].device->get_connected())) {
if (port == 0) {
strcpy(pname, BXPN_USB1_OPTION1);
} else {
strcpy(pname, BXPN_USB1_OPTION2);
}
if (!((usb_msd_device_t*)BX_USB_THIS hub[0].usb_port[port].device)->init(SIM->get_param_string(pname)->getptr())) {
usb_set_connect_status(port, USB_DEV_TYPE_DISK, 0);
} else {
BX_INFO(("HD on USB port #%d: '%s'", port+1, SIM->get_param_string(pname)->getptr()));
}
}
} else {
BX_USB_THIS hub[0].usb_port[port].status = 0;
BX_USB_THIS hub[0].usb_port[port].connect_changed = 1;
BX_USB_THIS hub[0].usb_port[port].enabled = 0;
BX_USB_THIS hub[0].usb_port[port].able_changed = 1;
BX_USB_THIS hub[0].usb_port[port].low_speed = 0;
BX_USB_THIS hub[0].usb_port[port].line_dminus = 0; // dminus=1 & dplus=0 = low speed (at idle time)
BX_USB_THIS hub[0].usb_port[port].line_dplus = 0; // dminus=0 & dplus=1 = high speed (at idle time)
if (type == USB_DEV_TYPE_MOUSE) {
BX_USB_THIS mouse_connected = 0;
} else if (type == USB_DEV_TYPE_KEYPAD) {
BX_USB_THIS keyboard_connected = 0;
} else if (type == USB_DEV_TYPE_DISK) {
if (BX_USB_THIS hub[0].usb_port[port].device != NULL) {
delete BX_USB_THIS hub[0].usb_port[port].device;
BX_USB_THIS hub[0].usb_port[port].device = NULL;
}
}
}
}
}
if (BX_USB_THIS hub[0].usb_port[port].device_num > -1) {
if (BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[port].device_num].dev_type == type) {
if (connected) {
@ -1712,22 +1834,6 @@ void bx_pciusb_c::usb_set_connect_status(Bit8u port, int type, bx_bool connected
set_irq_level(1);
}
}
if ((type == USB_DEV_TYPE_DISK) &&
(BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[port].device_num].devstate == NULL)) {
if (port == 0) {
strcpy(pname, BXPN_USB1_OPTION1);
} else {
strcpy(pname, BXPN_USB1_OPTION2);
}
s = BX_USB_THIS usb_msd_init(SIM->get_param_string(pname)->getptr());
if (s == NULL) {
usb_set_connect_status(port, USB_DEV_TYPE_DISK, 0);
} else {
BX_INFO(("HD on USB port #%d: '%s'", port+1, SIM->get_param_string(pname)->getptr()));
BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[port].device_num].devstate = (void*)s;
}
}
} else {
BX_USB_THIS hub[0].usb_port[port].status = 0;
BX_USB_THIS hub[0].usb_port[port].connect_changed = 1;
@ -1740,13 +1846,6 @@ void bx_pciusb_c::usb_set_connect_status(Bit8u port, int type, bx_bool connected
BX_USB_THIS mouse_connected = 0;
} else if (type == USB_DEV_TYPE_KEYPAD) {
BX_USB_THIS keyboard_connected = 0;
} else if (type == USB_DEV_TYPE_DISK) {
BX_USB_THIS disk_connected = 0;
s = (MSDState*)BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[port].device_num].devstate;
if (s != NULL) {
BX_USB_THIS usb_msd_handle_destroy(s);
BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[port].device_num].devstate = NULL;
}
}
}
}
@ -1883,277 +1982,159 @@ bx_bool bx_pciusb_c::usb_mouse_connected()
return BX_USB_THIS mouse_connected;
}
// Dumps the contents of a buffer to the log file
void bx_pciusb_c::dump_packet(Bit8u *data, unsigned size)
// Send an internal message to a USB device
void bx_pciusb_c::usb_send_msg(usb_device_t *dev, int msg)
{
char the_packet[256], str[16];
strcpy(the_packet, "Packet contents (in hex):");
unsigned offset = 0;
for (unsigned p=0; p<size; p++) {
if (!(p & 0x0F)) {
BX_DEBUG(("%s", the_packet));
sprintf(the_packet, " 0x%04X ", offset);
offset += 16;
}
sprintf(str, " %02X", data[p]);
strcat(the_packet, str);
}
if (strlen(the_packet))
BX_DEBUG(("%s", the_packet));
USBPacket p;
memset(&p, 0, sizeof(p));
p.pid = msg;
dev->handle_packet(&p);
}
// USB mass storage device support
// generic USB packet handler
int bx_pciusb_c::usb_msd_handle_data(MSDState *s, USBPacket *p)
#define SETUP_STATE_IDLE 0
#define SETUP_STATE_DATA 1
#define SETUP_STATE_ACK 2
usb_device_t::usb_device_t(void)
{
struct usb_msd_cbw cbw;
int ret = 0;
Bit8u devep = p->devep;
Bit8u *data = p->data;
memset((void*)&d, 0, sizeof(d));
}
int usb_device_t::handle_packet(USBPacket *p)
{
int l, ret = 0;
int len = p->len;
Bit8u *data = p->data;
switch (p->pid) {
case USB_TOKEN_OUT:
dump_packet(data, len);
if (devep != 2)
switch(p->pid) {
case USB_MSG_ATTACH:
d.state = USB_STATE_ATTACHED;
break;
case USB_MSG_DETACH:
d.state = USB_STATE_NOTATTACHED;
break;
case USB_MSG_RESET:
d.remote_wakeup = 0;
d.addr = 0;
d.state = USB_STATE_DEFAULT;
handle_reset();
break;
case USB_TOKEN_SETUP:
if (d.state < USB_STATE_DEFAULT || p->devaddr != d.addr)
return USB_RET_NODEV;
if (len != 8)
goto fail;
switch (s->mode) {
case USB_MSDM_CBW:
if (len != 31) {
BX_ERROR(("bad CBW len"));
goto fail;
}
memcpy(&cbw, data, 31);
if (dtoh32(cbw.sig) != 0x43425355) {
BX_ERROR(("bad signature %08x", dtoh32(cbw.sig)));
goto fail;
}
BX_DEBUG(("command on LUN %d", cbw.lun));
s->tag = dtoh32(cbw.tag);
s->data_len = dtoh32(cbw.data_len);
if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
} else if (cbw.flags & 0x80) {
s->mode = USB_MSDM_DATAIN;
} else {
s->mode = USB_MSDM_DATAOUT;
}
BX_DEBUG(("command tag 0x%x flags %08x len %d data %d",
s->tag, cbw.flags, cbw.cmd_len, s->data_len));
s->residue = 0;
s->scsi_dev->scsi_send_command(s->tag, cbw.cmd, cbw.lun);
if (s->residue == 0) {
if (s->mode == USB_MSDM_DATAIN) {
s->scsi_dev->scsi_read_data(s->tag);
} else if (s->mode == USB_MSDM_DATAOUT) {
s->scsi_dev->scsi_write_data(s->tag);
}
}
ret = len;
break;
case USB_MSDM_DATAOUT:
BX_DEBUG(("data out %d/%d", len, s->data_len));
if (len > (int)s->data_len)
goto fail;
s->usb_buf = data;
s->usb_len = len;
if (s->scsi_len) {
usb_msd_copy_data(s);
}
if (s->residue && s->usb_len) {
s->data_len -= s->usb_len;
if (s->data_len == 0)
s->mode = USB_MSDM_CSW;
s->usb_len = 0;
}
if (s->usb_len) {
BX_INFO(("deferring packet %p", p));
// TODO: defer packet
s->packet = p;
ret = USB_RET_ASYNC;
} else {
ret = len;
}
break;
default:
BX_ERROR(("usb_msd_handle_data: unexpected mode at USB_TOKEN_OUT"));
goto fail;
memcpy(d.setup_buf, data, 8);
d.setup_len = (d.setup_buf[7] << 8) | d.setup_buf[6];
d.setup_index = 0;
if (d.setup_buf[0] & USB_DIR_IN) {
ret = handle_control((d.setup_buf[0] << 8) | d.setup_buf[1],
(d.setup_buf[3] << 8) | d.setup_buf[2],
(d.setup_buf[5] << 8) | d.setup_buf[4],
d.setup_len, d.data_buf);
if (ret < 0)
return ret;
if (ret < d.setup_len)
d.setup_len = ret;
d.setup_state = SETUP_STATE_DATA;
} else {
if (d.setup_len == 0)
d.setup_state = SETUP_STATE_ACK;
else
d.setup_state = SETUP_STATE_DATA;
}
break;
case USB_TOKEN_IN:
if (devep != 1)
goto fail;
switch (s->mode) {
case USB_MSDM_DATAOUT:
if (s->data_len != 0 || len < 13)
goto fail;
// TODO: defer packet
s->packet = p;
ret = USB_RET_ASYNC;
if (d.state < USB_STATE_DEFAULT || p->devaddr != d.addr)
return USB_RET_NODEV;
switch(p->devep) {
case 0:
switch(d.setup_state) {
case SETUP_STATE_ACK:
if (!(d.setup_buf[0] & USB_DIR_IN)) {
d.setup_state = SETUP_STATE_IDLE;
ret = handle_control((d.setup_buf[0] << 8) | d.setup_buf[1],
(d.setup_buf[3] << 8) | d.setup_buf[2],
(d.setup_buf[5] << 8) | d.setup_buf[4],
d.setup_len, d.data_buf);
if (ret > 0)
ret = 0;
} else {
// return 0 byte
}
break;
case SETUP_STATE_DATA:
if (d.setup_buf[0] & USB_DIR_IN) {
l = d.setup_len - d.setup_index;
if (l > len)
l = len;
memcpy(data, d.data_buf + d.setup_index, l);
d.setup_index += l;
if (d.setup_index >= d.setup_len)
d.setup_state = SETUP_STATE_ACK;
ret = l;
} else {
d.setup_state = SETUP_STATE_IDLE;
goto fail;
}
break;
default:
goto fail;
}
break;
default:
ret = handle_data(p);
break;
}
break;
case USB_TOKEN_OUT:
if (d.state < USB_STATE_DEFAULT || p->devaddr != d.addr)
return USB_RET_NODEV;
switch(p->devep) {
case 0:
switch(d.setup_state) {
case SETUP_STATE_ACK:
if (d.setup_buf[0] & USB_DIR_IN) {
d.setup_state = SETUP_STATE_IDLE;
// transfer OK
} else {
// ignore additionnal output
}
break;
case SETUP_STATE_DATA:
if (!(d.setup_buf[0] & USB_DIR_IN)) {
l = d.setup_len - d.setup_index;
if (l > len)
l = len;
memcpy(d.data_buf + d.setup_index, data, l);
d.setup_index += l;
if (d.setup_index >= d.setup_len)
d.setup_state = SETUP_STATE_ACK;
ret = l;
} else {
d.setup_state = SETUP_STATE_IDLE;
goto fail;
}
break;
default:
goto fail;
}
break;
case USB_MSDM_CSW:
BX_DEBUG(("command status %d tag 0x%x, len %d",
s->result, s->tag, len));
if (len < 13)
return ret;
s->usb_len = len;
s->usb_buf = data;
usb_msd_send_status(s);
s->mode = USB_MSDM_CBW;
ret = 13;
break;
case USB_MSDM_DATAIN:
BX_DEBUG(("data in %d/%d", len, s->data_len));
if (len > (int)s->data_len)
len = s->data_len;
s->usb_buf = data;
s->usb_len = len;
if (s->scsi_len) {
usb_msd_copy_data(s);
}
if (s->residue && s->usb_len) {
s->data_len -= s->usb_len;
memset(s->usb_buf, 0, s->usb_len);
if (s->data_len == 0)
s->mode = USB_MSDM_CSW;
s->usb_len = 0;
}
if (s->usb_len) {
BX_INFO(("deferring packet %p", p));
// TODO: defer packet
s->packet = p;
ret = USB_RET_ASYNC;
} else {
ret = len;
}
break;
default:
BX_ERROR(("usb_msd_handle_data: unexpected mode at USB_TOKEN_IN"));
goto fail;
}
if (ret > 0) dump_packet(data, ret);
break;
default:
ret = handle_data(p);
break;
}
break;
default:
BX_ERROR(("usb_msd_handle_data: bad token"));
fail:
fail:
ret = USB_RET_STALL;
break;
}
return ret;
}
void bx_pciusb_c::usb_msd_copy_data(MSDState *s)
{
Bit32u len = s->usb_len;
if (len > s->scsi_len)
len = s->scsi_len;
if (s->mode == USB_MSDM_DATAIN) {
memcpy(s->usb_buf, s->scsi_buf, len);
} else {
memcpy(s->scsi_buf, s->usb_buf, len);
}
s->usb_len -= len;
s->scsi_len -= len;
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->scsi_read_data(s->tag);
} else if (s->mode == USB_MSDM_DATAOUT) {
s->scsi_dev->scsi_write_data(s->tag);
}
}
}
void bx_pciusb_c::usb_msd_send_status(MSDState *s)
{
struct usb_msd_csw csw;
csw.sig = htod32(0x53425355);
csw.tag = htod32(s->tag);
csw.residue = s->residue;
csw.status = s->result;
memcpy(s->usb_buf, &csw, 13);
}
void bx_pciusb_c::usb_msd_command_complete(void *opaque, int reason, Bit32u tag, Bit32u arg)
{
MSDState *s = (MSDState *)opaque;
USBPacket *p = s->packet;
if (tag != s->tag) {
BX_ERROR(("usb-msd_command_complete: unexpected SCSI tag 0x%x", tag));
}
if (reason == SCSI_REASON_DONE) {
BX_DEBUG(("command complete %d", arg));
s->residue = s->data_len;
s->result = arg != 0;
if (s->packet) {
if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
BX_USB_THIS 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;
} else if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
}
return;
}
s->scsi_len = arg;
s->scsi_buf = s->scsi_dev->scsi_get_buf(tag);
if (p) {
BX_USB_THIS usb_msd_copy_data(s);
if (s->usb_len == 0) {
BX_INFO(("packet complete %p", p));
s->packet = NULL;
}
}
}
void bx_pciusb_c::usb_msd_handle_destroy(MSDState *s)
{
delete s->scsi_dev;
s->hdimage->close();
delete s->hdimage;
delete s;
}
MSDState* bx_pciusb_c::usb_msd_init(const char *filename)
{
MSDState *s = new MSDState;
memset(s, 0, sizeof(MSDState));
s->hdimage = new default_image_t();
if (s->hdimage->open(filename) < 0) {
BX_ERROR(("could not open hard drive image file '%s'", filename));
return NULL;
} else {
s->scsi_dev = new scsi_device_t(s->hdimage, 0, usb_msd_command_complete, (void*)s);
s->mode = USB_MSDM_CBW;
return s;
}
}
// USB runtime parameter handler
@ -2168,7 +2149,11 @@ const char *bx_pciusb_c::usb_param_handler(bx_param_string_c *param, int set, co
if (!strcmp(pname, BXPN_USB1_PORT1)) {
BX_INFO(("USB port #1 experimental device change"));
if (!strcmp(val, "none") && BX_USB_THIS hub[0].usb_port[0].status) {
type = BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[0].device_num].dev_type;
if (BX_USB_THIS hub[0].usb_port[0].device != NULL) {
type = BX_USB_THIS hub[0].usb_port[0].device->get_type();
} else {
type = BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[0].device_num].dev_type;
}
usb_set_connect_status(0, type, 0);
} else if (strcmp(val, "none") && !BX_USB_THIS hub[0].usb_port[0].status) {
init_device(0, val);
@ -2178,7 +2163,11 @@ const char *bx_pciusb_c::usb_param_handler(bx_param_string_c *param, int set, co
} else if (!strcmp(pname, BXPN_USB1_PORT2)) {
BX_INFO(("USB port #2 experimental device change"));
if (!strcmp(val, "none") && BX_USB_THIS hub[0].usb_port[1].status) {
type = BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[1].device_num].dev_type;
if (BX_USB_THIS hub[0].usb_port[1].device != NULL) {
type = BX_USB_THIS hub[0].usb_port[1].device->get_type();
} else {
type = BX_USB_THIS hub[0].device[BX_USB_THIS hub[0].usb_port[1].device_num].dev_type;
}
usb_set_connect_status(1, type, 0);
} else if (strcmp(val, "none") && !BX_USB_THIS hub[0].usb_port[1].status) {
init_device(1, val);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: pciusb.h,v 1.22 2007-03-16 18:23:13 vruppert Exp $
// $Id: pciusb.h,v 1.23 2007-03-18 11:17:28 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004 MandrakeSoft S.A.
@ -25,6 +25,7 @@
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Benjamin D Lunt (fys at frontiernet net) coded most of this usb emulation.
// USB mass storage device support and SCSI emulation layer ported from Qemu
#ifndef BX_IODEV_PCIUSB_H
#define BX_IODEV_PCIUSB_H
@ -41,20 +42,84 @@
#define BX_USB_CONFDEV 1 /* only 1 USB hub currently */
#define USB_NUM_PORTS 2 /* UHCI supports 2 ports per root hub */
#define USB_CUR_DEVS 3
#define USB_CUR_DEVS 2
#define USB_TOKEN_IN 0x69
#define USB_TOKEN_OUT 0xE1
#define USB_TOKEN_SETUP 0x2D
#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)
class scsi_device_t;
class device_image_t;
#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_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
// USB 1.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
// USB 2.0
#define USB_DT_DEVICE_QUALIFIER 0x06
#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_DT_INTERFACE_POWER 0x08
struct USBPacket {
int pid;
@ -64,45 +129,6 @@ struct USBPacket {
int len;
};
enum USBMSDMode {
USB_MSDM_CBW,
USB_MSDM_DATAOUT,
USB_MSDM_DATAIN,
USB_MSDM_CSW
};
typedef struct {
enum USBMSDMode mode;
Bit32u scsi_len;
Bit8u *scsi_buf;
Bit32u usb_len;
Bit8u *usb_buf;
Bit32u data_len;
Bit32u residue;
Bit32u tag;
int result;
device_image_t *hdimage;
scsi_device_t *scsi_dev;
USBPacket *packet;
} MSDState;
struct usb_msd_cbw {
Bit32u sig;
Bit32u tag;
Bit32u data_len;
Bit8u flags;
Bit8u lun;
Bit8u cmd_len;
Bit8u cmd[16];
};
struct usb_msd_csw {
Bit32u sig;
Bit32u tag;
Bit32u residue;
Bit8u status;
};
// device requests
enum { GET_STATUS=0, CLEAR_FEATURE, SET_FEATURE=3, SET_ADDRESS=5, GET_DESCRIPTOR=6, SET_DESCRIPTOR,
GET_CONFIGURATION, SET_CONFIGURATION,
@ -114,11 +140,6 @@ enum { GET_STATUS=0, CLEAR_FEATURE, SET_FEATURE=3, SET_ADDRESS=5, GET_DESCRIPTOR
#define SET_FEATURE_TEST_MODE 0 /////////TODO: I don't know yet what this value is to be
// Descriptor types
enum { DEVICE=1, CONFIG, STRING, INTERFACE, ENDPOINT, // USB 1.1
DEVICE_QUALIFIER, OTHER_SPEED_CONFIG, INTERFACE_POWER // USB 2.0
};
#define STATE_DEFAULT 0
#define STATE_ADDRESS 1
#define STATE_CONFIGURED 2
@ -138,10 +159,50 @@ struct KEYPAD {
Bit8u keypad_packet[8];
};
#define USB_DEV_TYPE_NONE 0
#define USB_DEV_TYPE_MOUSE 1
#define USB_DEV_TYPE_KEYPAD 2
#define USB_DEV_TYPE_DISK 3
enum usbdev_type {
USB_DEV_TYPE_NONE=0,
USB_DEV_TYPE_MOUSE,
USB_DEV_TYPE_KEYPAD,
USB_DEV_TYPE_DISK
};
void usb_dump_packet(Bit8u *data, unsigned size);
int set_usb_string(Bit8u *buf, const char *str);
class usb_device_t : public logfunctions {
public:
usb_device_t(void);
virtual ~usb_device_t(void) {}
virtual int handle_packet(USBPacket *p);
virtual void handle_reset() {}
virtual int handle_control(int request, int value, int index, int length, Bit8u *data) {return 0;}
virtual int handle_data(USBPacket *p) {return 0;}
bx_bool get_connected() {return d.connected;}
usbdev_type get_type() {return d.type;}
int get_speed() {return d.speed;}
Bit8u get_address() {return d.addr;}
protected:
struct {
enum usbdev_type type;
bx_bool connected;
int speed;
Bit8u addr;
Bit8u config;
char devname[32];
int state;
Bit8u setup_buf[8];
Bit8u data_buf[1024];
int remote_wakeup;
int setup_state;
int setup_len;
int setup_index;
} d;
};
// set it to 1 (align on byte) and save so we can pop it
#pragma pack(push, 1)
@ -235,7 +296,6 @@ struct USB_DEVICE {
Bit8u unicode_str[64];
} string[6];
} function; // currently, we only support 1 function
void *devstate;
};
#pragma pack(pop)
@ -349,6 +409,7 @@ typedef struct {
struct {
// our data
int device_num; // device number on this hub
usb_device_t *device; // device connected to this port
// bit reps of actual port
bx_bool suspend;
@ -438,7 +499,6 @@ private:
bx_bool last_connect;
bx_bool keyboard_connected;
bx_bool mouse_connected;
bx_bool disk_connected;
USBPacket usb_packet;
@ -448,7 +508,6 @@ private:
static void usb_timer_handler(void *);
void usb_timer(void);
bx_bool DoTransfer(Bit32u address, Bit32u queue_num, struct TD *);
void dump_packet(Bit8u *data, unsigned size);
unsigned GetDescriptor(struct USB_DEVICE *, struct REQUEST_PACKET *);
void set_status(struct TD *td, bx_bool stalled, bx_bool data_buffer_error, bx_bool babble,
bx_bool nak, bx_bool crc_time_out, bx_bool bitstuff_error, Bit16u act_len);
@ -459,13 +518,7 @@ private:
Bit32u read(Bit32u address, unsigned io_len);
void write(Bit32u address, Bit32u value, unsigned io_len);
#endif
// USB mass storage device support
void usb_msd_copy_data(MSDState *s);
void usb_msd_send_status(MSDState *s);
static void usb_msd_command_complete(void *opaque, int reason, Bit32u tag, Bit32u arg);
int usb_msd_handle_data(MSDState *s, USBPacket *p);
void usb_msd_handle_destroy(MSDState *s);
MSDState* usb_msd_init(const char *filename);
void usb_send_msg(usb_device_t *dev, int msg);
};
#endif

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: pciusb_devs.h,v 1.8 2007-03-14 18:05:46 vruppert Exp $
// $Id: pciusb_devs.h,v 1.9 2007-03-18 11:17:28 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004 MandrakeSoft S.A.
@ -36,7 +36,6 @@
// defines
#define USB_CYPRESS 1
#define USB_KEYPAD 1
#define USB_HARD_DRIVE 1
// don't forget to modify USB_CUR_DEVS to reflect devices
@ -63,7 +62,7 @@
// device descriptor
BX_USB_THIS hub[0].device[0].function.device_descr.len = 18;
BX_USB_THIS hub[0].device[0].function.device_descr.type = DEVICE;
BX_USB_THIS hub[0].device[0].function.device_descr.type = USB_DT_DEVICE;
BX_USB_THIS hub[0].device[0].function.device_descr.usb_ver = 0x0100;
BX_USB_THIS hub[0].device[0].function.device_descr._class = 0;
BX_USB_THIS hub[0].device[0].function.device_descr.subclass = 0;
@ -79,7 +78,7 @@
// config descriptor
BX_USB_THIS hub[0].device[0].function.device_config[0].len = 9;
BX_USB_THIS hub[0].device[0].function.device_config[0].type = CONFIG;
BX_USB_THIS hub[0].device[0].function.device_config[0].type = USB_DT_CONFIG;
BX_USB_THIS hub[0].device[0].function.device_config[0].tot_len = 34; // size of config+interface+endpt+hid
BX_USB_THIS hub[0].device[0].function.device_config[0].interfaces = 1;
BX_USB_THIS hub[0].device[0].function.device_config[0].config_val = 1;
@ -90,7 +89,7 @@
// interface descriptor
// 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x02, 0x05, // interface descriptor
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].size = 9;
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].type = INTERFACE;
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].type = USB_DT_INTERFACE;
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].interface_num = 0;
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].alternate = 0;
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].num_endpts = 1;
@ -102,7 +101,7 @@
// endpoint descriptor
// 0x07, 0x05, 0x81, 0x03, 0x03, 0x00, 0x0A, // endpoint descriptor
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].endpts[0].size = 7;
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].endpts[0].type = ENDPOINT;
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].endpts[0].type = USB_DT_ENDPOINT;
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].endpts[0].endpt = 0x81;
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].endpts[0].attrib = 3;
BX_USB_THIS hub[0].device[0].function.device_config[0].Interface[0].endpts[0].max_size = 3;
@ -201,7 +200,7 @@
// device descriptor
BX_USB_THIS hub[0].device[1].function.device_descr.len = 18;
BX_USB_THIS hub[0].device[1].function.device_descr.type = DEVICE;
BX_USB_THIS hub[0].device[1].function.device_descr.type = USB_DT_DEVICE;
BX_USB_THIS hub[0].device[1].function.device_descr.usb_ver = 0x0110;
BX_USB_THIS hub[0].device[1].function.device_descr._class = 0;
BX_USB_THIS hub[0].device[1].function.device_descr.subclass = 0;
@ -217,7 +216,7 @@
// config descriptor
BX_USB_THIS hub[0].device[1].function.device_config[0].len = 9;
BX_USB_THIS hub[0].device[1].function.device_config[0].type = CONFIG;
BX_USB_THIS hub[0].device[1].function.device_config[0].type = USB_DT_CONFIG;
BX_USB_THIS hub[0].device[1].function.device_config[0].tot_len = 59; // size of config+interface+endpt+hid
BX_USB_THIS hub[0].device[1].function.device_config[0].interfaces = 2;
BX_USB_THIS hub[0].device[1].function.device_config[0].config_val = 1;
@ -228,7 +227,7 @@
// interface descriptor #1
// 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x01, 0x01, 0x05, // interface descriptor
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].size = 9;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].type = INTERFACE;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].type = USB_DT_INTERFACE;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].interface_num = 0;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].alternate = 0;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].num_endpts = 1;
@ -262,7 +261,7 @@
// endpoint descriptor #1
// 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x0A, // endpoint descriptor
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].endpts[0].size = 7;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].endpts[0].type = ENDPOINT;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].endpts[0].type = USB_DT_ENDPOINT;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].endpts[0].endpt = 0x81;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].endpts[0].attrib = 3;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[0].endpts[0].max_size = 8;
@ -291,7 +290,7 @@
// interface descriptor #2
// 0x09, 0x04, 0x01, 0x00, 0x01, 0x03, 0x01, 0x02, 0x06, // interface descriptor
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].size = 9;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].type = INTERFACE;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].type = USB_DT_INTERFACE;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].interface_num = 1;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].alternate = 0;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].num_endpts = 1;
@ -325,7 +324,7 @@
// endpoint descriptor #2
// 0x07, 0x05, 0x82, 0x03, 0x05, 0x00, 0x0A, // endpoint descriptor
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].endpts[0].size = 7;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].endpts[0].type = ENDPOINT;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].endpts[0].type = USB_DT_ENDPOINT;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].endpts[0].endpt = 0x82;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].endpts[0].attrib = 3;
BX_USB_THIS hub[0].device[1].function.device_config[0].Interface[1].endpts[0].max_size = 5;
@ -384,151 +383,3 @@
#endif // USB_KEYPAD
///////////////////////////////////////////////////////////////////////////////////////////////
// USB mass storage device
#if USB_HARD_DRIVE
BX_USB_THIS hub[0].device[2].connect_status = 0;
BX_USB_THIS hub[0].device[2].dev_type = USB_DEV_TYPE_DISK;
BX_USB_THIS hub[0].device[2].state = STATE_DEFAULT;
BX_USB_THIS hub[0].device[2].address = 0;
BX_USB_THIS hub[0].device[2].alt_interface = 0;
BX_USB_THIS hub[0].device[2].Interface = 0;
BX_USB_THIS hub[0].device[2].config = 0;
BX_USB_THIS hub[0].device[2].endpt = 1;
BX_USB_THIS hub[0].device[2].function.direction = 0;
BX_USB_THIS hub[0].device[2].function.configs = 1; // only one config in this device
BX_USB_THIS hub[0].device[2].low_speed = 0;
BX_USB_THIS hub[0].device[2].in_stall = 0;
BX_USB_THIS hub[0].device[2].stall_once = 0x00; // stall on the first setup packet (set bit 0)
// device descriptor
BX_USB_THIS hub[0].device[2].function.device_descr.len = 18;
BX_USB_THIS hub[0].device[2].function.device_descr.type = DEVICE;
BX_USB_THIS hub[0].device[2].function.device_descr.usb_ver = 0x0200;
BX_USB_THIS hub[0].device[2].function.device_descr._class = 0;
BX_USB_THIS hub[0].device[2].function.device_descr.subclass = 0;
BX_USB_THIS hub[0].device[2].function.device_descr.protocol = 0;
BX_USB_THIS hub[0].device[2].function.device_descr.max_packet_size = 64;
BX_USB_THIS hub[0].device[2].function.device_descr.vendorid = 0x0000;
BX_USB_THIS hub[0].device[2].function.device_descr.productid = 0x0000;
BX_USB_THIS hub[0].device[2].function.device_descr.device_rel = 0x0100;
BX_USB_THIS hub[0].device[2].function.device_descr.manuf_indx = 1;
BX_USB_THIS hub[0].device[2].function.device_descr.prod_indx = 2;
BX_USB_THIS hub[0].device[2].function.device_descr.serial_indx = 3;
BX_USB_THIS hub[0].device[2].function.device_descr.configs = 1;
// config descriptor
BX_USB_THIS hub[0].device[2].function.device_config[0].len = 9;
BX_USB_THIS hub[0].device[2].function.device_config[0].type = CONFIG;
BX_USB_THIS hub[0].device[2].function.device_config[0].tot_len = 39; // size of config+interface+endpt+hid
BX_USB_THIS hub[0].device[2].function.device_config[0].interfaces = 1;
BX_USB_THIS hub[0].device[2].function.device_config[0].config_val = 1;
BX_USB_THIS hub[0].device[2].function.device_config[0].config_indx = 0;
BX_USB_THIS hub[0].device[2].function.device_config[0].attrbs = 0x80; //
BX_USB_THIS hub[0].device[2].function.device_config[0].max_power = 100;
// interface descriptor
// 0x09, 0x04, 0x00, 0x00, 0x03, 0x08, 0x06, 0x50, 0x00, // interface descriptor
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].size = 9;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].type = INTERFACE;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].interface_num = 0;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].alternate = 0;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].num_endpts = 3;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].iclass = 8;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].subclass = 6;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].protocol = 0x50;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].str_indx = 0;
// endpoint descriptor
// 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, // endpoint descriptor
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[0].size = 7;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[0].type = ENDPOINT;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[0].endpt = 0x81;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[0].attrib = 2;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[0].max_size = 64;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[0].interval = 0x00;
// endpoint descriptor
// 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, // endpoint descriptor
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[1].size = 7;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[1].type = ENDPOINT;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[1].endpt = 0x02;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[1].attrib = 2;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[1].max_size = 64;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[1].interval = 0x00;
// endpoint descriptor
// 0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x01, // endpoint descriptor
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[2].size = 7;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[2].type = ENDPOINT;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[2].endpt = 0x83;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[2].attrib = 3;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[2].max_size = 64;
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].endpts[2].interval = 0x01;
// string descriptors
BX_USB_THIS hub[0].device[2].function.str_descriptor.size = 0x04;
BX_USB_THIS hub[0].device[2].function.str_descriptor.type = 0x03;
BX_USB_THIS hub[0].device[2].function.str_descriptor.langid[0] = 0x0409;
// string #1
BX_USB_THIS hub[0].device[2].function.string[0].size = 36;
BX_USB_THIS hub[0].device[2].function.string[0].type = 3;
Bit8u dev3_str_1[64] = { 'U', 0x00, 'S', 0x00, 'B', 0x00, ' ', 0x00, 'H', 0x00, 'a', 0x00, 'r', 0x00,
'd', 0x00, ' ', 0x00, 'D', 0x00, 'r', 0x00, 'i', 0x00, 'v', 0x00, 'e', 0x00, ' ', 0x00, 'S', 0x00,
'0', 0x00,
};
memcpy(BX_USB_THIS hub[0].device[2].function.string[0].unicode_str, dev3_str_1, 34);
// string #2
BX_USB_THIS hub[0].device[2].function.string[1].size = 36;
BX_USB_THIS hub[0].device[2].function.string[1].type = 3;
Bit8u dev3_str_2[64] = { 'U', 0x00, 'S', 0x00, 'B', 0x00, ' ', 0x00, 'H', 0x00, 'a', 0x00, 'r', 0x00,
'd', 0x00, ' ', 0x00, 'D', 0x00, 'r', 0x00, 'i', 0x00, 'v', 0x00, 'e', 0x00, ' ', 0x00, 'S', 0x00,
'1', 0x00,
};
memcpy(BX_USB_THIS hub[0].device[2].function.string[1].unicode_str, dev3_str_2, 34);
// string #3
BX_USB_THIS hub[0].device[2].function.string[2].size = 36;
BX_USB_THIS hub[0].device[2].function.string[2].type = 3;
Bit8u dev3_str_3[64] = { 'U', 0x00, 'S', 0x00, 'B', 0x00, ' ', 0x00, 'H', 0x00, 'a', 0x00, 'r', 0x00,
'd', 0x00, ' ', 0x00, 'D', 0x00, 'r', 0x00, 'i', 0x00, 'v', 0x00, 'e', 0x00, ' ', 0x00, 'S', 0x00,
'2', 0x00,
};
memcpy(BX_USB_THIS hub[0].device[2].function.string[2].unicode_str, dev3_str_3, 34);
// string #4
BX_USB_THIS hub[0].device[2].function.string[3].size = 36;
BX_USB_THIS hub[0].device[2].function.string[3].type = 3;
Bit8u dev3_str_4[64] = { 'U', 0x00, 'S', 0x00, 'B', 0x00, ' ', 0x00, 'H', 0x00, 'a', 0x00, 'r', 0x00,
'd', 0x00, ' ', 0x00, 'D', 0x00, 'r', 0x00, 'i', 0x00, 'v', 0x00, 'e', 0x00, ' ', 0x00, 'S', 0x00,
'3', 0x00,
};
memcpy(BX_USB_THIS hub[0].device[2].function.string[3].unicode_str, dev3_str_4, 34);
// string #5
BX_USB_THIS hub[0].device[2].function.string[4].size = 36;
BX_USB_THIS hub[0].device[2].function.string[4].type = 3;
Bit8u dev3_str_5[64] = { 'U', 0x00, 'S', 0x00, 'B', 0x00, ' ', 0x00, 'H', 0x00, 'a', 0x00, 'r', 0x00,
'd', 0x00, ' ', 0x00, 'D', 0x00, 'r', 0x00, 'i', 0x00, 'v', 0x00, 'e', 0x00, ' ', 0x00, 'S', 0x00,
'4', 0x00,
};
memcpy(BX_USB_THIS hub[0].device[2].function.string[3].unicode_str, dev3_str_5, 34);
// this device has no key conversion table
BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].lookup_cnt = 0;
memset(&BX_USB_THIS hub[0].device[2].function.device_config[0].Interface[0].lookup, 0, sizeof(struct KEYPAD) * KEYPAD_LEN);
BX_USB_THIS hub[0].device[2].devstate = NULL;
#endif // USB_HARD_DRIVE
// Another device would go here.

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: scsi_device.cc,v 1.1 2007-03-16 18:23:13 vruppert Exp $
// $Id: scsi_device.cc,v 1.2 2007-03-18 11:17:28 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2007 Volker Ruppert
@ -28,6 +28,7 @@
#define NO_DEVICE_INCLUDES
#include "iodev.h"
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB
#include "hdimage.h"
#include "scsi_device.h"
@ -46,6 +47,9 @@ scsi_device_t::scsi_device_t(device_image_t *_hdimage, int _tcq,
completion = _completion;
dev = _dev;
cluster_size = 1;
put("SCSI");
settype(PCIUSBLOG);
}
scsi_device_t::~scsi_device_t(void)
@ -422,6 +426,7 @@ Bit32s scsi_device_t::scsi_send_command(Bit32u tag, Bit8u *buf, int lun)
memset(outbuf, 0, 8);
if (type == SCSIDEV_TYPE_CDROM) {
// TODO: get cdrom capacity
nb_sectors = 0;
} else {
nb_sectors = hdimage->hd_size / 512;
}
@ -507,3 +512,5 @@ Bit32s scsi_device_t::scsi_send_command(Bit32u tag, Bit8u *buf, int lun)
return len;
}
}
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: scsi_device.h,v 1.1 2007-03-16 18:23:13 vruppert Exp $
// $Id: scsi_device.h,v 1.2 2007-03-18 11:17:28 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2007 Volker Ruppert
@ -26,7 +26,6 @@
typedef void (*scsi_completionfn)(void *opaque, int reason, Bit32u tag,
Bit32u arg);
class scsi_device_t;
class device_image_t;
enum scsidev_type {
SCSIDEV_TYPE_DISK,

510
bochs/iodev/usb_msd.cc Normal file
View File

@ -0,0 +1,510 @@
/////////////////////////////////////////////////////////////////////////
// $Id: usb_msd.cc,v 1.1 2007-03-18 11:17:28 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2007 Volker Ruppert
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// USB mass storage device support ported from the Qemu project
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE
#include "iodev.h"
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB
#include "hdimage.h"
#include "scsi_device.h"
#include "usb_msd.h"
#define LOG_THIS
struct usb_msd_cbw {
Bit32u sig;
Bit32u tag;
Bit32u data_len;
Bit8u flags;
Bit8u lun;
Bit8u cmd_len;
Bit8u cmd[16];
};
struct usb_msd_csw {
Bit32u sig;
Bit32u tag;
Bit32u residue;
Bit8u status;
};
// USB requests
#define MassStorageReset 0xff
#define GetMaxLun 0xfe
static const Bit8u bx_msd_dev_descriptor[] = {
0x12, /* u8 bLength; */
0x01, /* u8 bDescriptorType; Device */
0x00, 0x02, /* u16 bcdUSB; v2.0 */
0x00, /* u8 bDeviceClass; */
0x00, /* u8 bDeviceSubClass; */
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
0x40, /* u8 bMaxPacketSize0; 64 Bytes */
/* Vendor and product id are arbitrary. */
0x00, 0x00, /* u16 idVendor; */
0x00, 0x00, /* u16 idProduct; */
0x00, 0x01, /* u16 bcdDevice */
0x01, /* u8 iManufacturer; */
0x02, /* u8 iProduct; */
0x03, /* u8 iSerialNumber; */
0x01 /* u8 bNumConfigurations; */
};
static const Bit8u bx_msd_config_descriptor[] = {
/* 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; */
/* 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; */
/* 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; */
/* 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; */
};
usb_msd_device_t::usb_msd_device_t(void)
{
d.type = USB_DEV_TYPE_DISK;
d.speed = USB_SPEED_FULL;
memset((void*)&s, 0, sizeof(MSDState));
put("USBMS");
settype(PCIUSBLOG);
}
usb_msd_device_t::~usb_msd_device_t(void)
{
delete s.scsi_dev;
s.hdimage->close();
delete s.hdimage;
}
bx_bool usb_msd_device_t::init(const char *filename)
{
s.hdimage = new default_image_t();
if (s.hdimage->open(filename) < 0) {
BX_ERROR(("could not open hard drive image file '%s'", filename));
return 0;
} else {
s.scsi_dev = new scsi_device_t(s.hdimage, 0, usb_msd_command_complete, (void*)this);
s.mode = USB_MSDM_CBW;
d.connected = 1;
return 1;
}
}
void usb_msd_device_t::handle_reset()
{
BX_DEBUG(("Reset"));
s.mode = USB_MSDM_CBW;
}
int usb_msd_device_t::handle_control(int request, int value, int index, int length, Bit8u *data)
{
int ret = 0;
switch (request) {
case DeviceRequest | USB_REQ_GET_STATUS:
data[0] = (1 << USB_DEVICE_SELF_POWERED) |
(d.remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
data[1] = 0x00;
ret = 2;
break;
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
if (value == USB_DEVICE_REMOTE_WAKEUP) {
d.remote_wakeup = 0;
} else {
goto fail;
}
ret = 0;
break;
case DeviceOutRequest | USB_REQ_SET_FEATURE:
if (value == USB_DEVICE_REMOTE_WAKEUP) {
d.remote_wakeup = 1;
} else {
goto fail;
}
ret = 0;
break;
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
d.addr = value;
ret = 0;
break;
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
switch(value >> 8) {
case USB_DT_DEVICE:
memcpy(data, bx_msd_dev_descriptor, sizeof(bx_msd_dev_descriptor));
ret = sizeof(bx_msd_dev_descriptor);
break;
case USB_DT_CONFIG:
memcpy(data, bx_msd_config_descriptor, sizeof(bx_msd_config_descriptor));
ret = sizeof(bx_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, "BOCHS");
break;
case 2:
// product description
ret = set_usb_string(data, "BOCHS USB HARDDRIVE");
break;
case 3:
// serial number
ret = set_usb_string(data, "1");
break;
default:
goto fail;
}
break;
case USB_DT_DEVICE_QUALIFIER:
// device qualifier
data[0] = 10;
data[1] = USB_DT_DEVICE_QUALIFIER;
memcpy(data+2, bx_msd_dev_descriptor+2, 6);
data[8] = 1;
data[9] = 0;
ret = 10;
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;
break;
case DeviceOutRequest | USB_REQ_SET_INTERFACE:
ret = 0;
break;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
if (value == 0 && index != 0x81) { /* clear ep halt */
goto fail;
}
ret = 0;
break;
// Class specific requests
case MassStorageReset:
s.mode = USB_MSDM_CBW;
ret = 0;
break;
case GetMaxLun:
data[0] = 0;
ret = 1;
break;
default:
fail:
ret = USB_RET_STALL;
break;
}
return ret;
}
int usb_msd_device_t::handle_data(USBPacket *p)
{
struct usb_msd_cbw cbw;
int ret = 0;
Bit8u devep = p->devep;
Bit8u *data = p->data;
int len = p->len;
switch (p->pid) {
case USB_TOKEN_OUT:
usb_dump_packet(data, len);
if (devep != 2)
goto fail;
switch (s.mode) {
case USB_MSDM_CBW:
if (len != 31) {
BX_ERROR(("bad CBW len"));
goto fail;
}
memcpy(&cbw, data, 31);
if (dtoh32(cbw.sig) != 0x43425355) {
BX_ERROR(("bad signature %08x", dtoh32(cbw.sig)));
goto fail;
}
BX_DEBUG(("command on LUN %d", cbw.lun));
s.tag = dtoh32(cbw.tag);
s.data_len = dtoh32(cbw.data_len);
if (s.data_len == 0) {
s.mode = USB_MSDM_CSW;
} else if (cbw.flags & 0x80) {
s.mode = USB_MSDM_DATAIN;
} else {
s.mode = USB_MSDM_DATAOUT;
}
BX_DEBUG(("command tag 0x%x flags %08x len %d data %d",
s.tag, cbw.flags, cbw.cmd_len, s.data_len));
s.residue = 0;
s.scsi_dev->scsi_send_command(s.tag, cbw.cmd, cbw.lun);
if (s.residue == 0) {
if (s.mode == USB_MSDM_DATAIN) {
s.scsi_dev->scsi_read_data(s.tag);
} else if (s.mode == USB_MSDM_DATAOUT) {
s.scsi_dev->scsi_write_data(s.tag);
}
}
ret = len;
break;
case USB_MSDM_DATAOUT:
BX_DEBUG(("data out %d/%d", len, s.data_len));
if (len > (int)s.data_len)
goto fail;
s.usb_buf = data;
s.usb_len = len;
if (s.scsi_len) {
copy_data();
}
if (s.residue && s.usb_len) {
s.data_len -= s.usb_len;
if (s.data_len == 0)
s.mode = USB_MSDM_CSW;
s.usb_len = 0;
}
if (s.usb_len) {
BX_INFO(("deferring packet %p", p));
// TODO: defer packet
s.packet = p;
ret = USB_RET_ASYNC;
} else {
ret = len;
}
break;
default:
BX_ERROR(("USB MSD handle_data: unexpected mode at USB_TOKEN_OUT"));
goto fail;
}
break;
case USB_TOKEN_IN:
if (devep != 1)
goto fail;
switch (s.mode) {
case USB_MSDM_DATAOUT:
if (s.data_len != 0 || len < 13)
goto fail;
// TODO: defer packet
s.packet = p;
ret = USB_RET_ASYNC;
break;
case USB_MSDM_CSW:
BX_DEBUG(("command status %d tag 0x%x, len %d",
s.result, s.tag, len));
if (len < 13)
return ret;
s.usb_len = len;
s.usb_buf = data;
send_status();
s.mode = USB_MSDM_CBW;
ret = 13;
break;
case USB_MSDM_DATAIN:
BX_DEBUG(("data in %d/%d", len, s.data_len));
if (len > (int)s.data_len)
len = s.data_len;
s.usb_buf = data;
s.usb_len = len;
if (s.scsi_len) {
copy_data();
}
if (s.residue && s.usb_len) {
s.data_len -= s.usb_len;
memset(s.usb_buf, 0, s.usb_len);
if (s.data_len == 0)
s.mode = USB_MSDM_CSW;
s.usb_len = 0;
}
if (s.usb_len) {
BX_INFO(("deferring packet %p", p));
// TODO: defer packet
s.packet = p;
ret = USB_RET_ASYNC;
} else {
ret = len;
}
break;
default:
BX_ERROR(("USB MSD handle_data: unexpected mode at USB_TOKEN_IN"));
goto fail;
}
if (ret > 0) usb_dump_packet(data, ret);
break;
default:
BX_ERROR(("USB MSD handle_data: bad token"));
fail:
ret = USB_RET_STALL;
break;
}
return ret;
}
void usb_msd_device_t::copy_data()
{
Bit32u len = s.usb_len;
if (len > s.scsi_len)
len = s.scsi_len;
if (s.mode == USB_MSDM_DATAIN) {
memcpy(s.usb_buf, s.scsi_buf, len);
} else {
memcpy(s.scsi_buf, s.usb_buf, len);
}
s.usb_len -= len;
s.scsi_len -= len;
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->scsi_read_data(s.tag);
} else if (s.mode == USB_MSDM_DATAOUT) {
s.scsi_dev->scsi_write_data(s.tag);
}
}
}
void usb_msd_device_t::send_status()
{
struct usb_msd_csw csw;
csw.sig = htod32(0x53425355);
csw.tag = htod32(s.tag);
csw.residue = s.residue;
csw.status = s.result;
memcpy(s.usb_buf, &csw, 13);
}
void usb_msd_device_t::usb_msd_command_complete(void *this_ptr, int reason, Bit32u tag, Bit32u arg)
{
usb_msd_device_t *class_ptr = (usb_msd_device_t *) this_ptr;
class_ptr->command_complete(reason, tag, arg);
}
void usb_msd_device_t::command_complete(int reason, Bit32u tag, Bit32u arg)
{
USBPacket *p = s.packet;
if (tag != s.tag) {
BX_ERROR(("usb-msd_command_complete: unexpected SCSI tag 0x%x", tag));
}
if (reason == SCSI_REASON_DONE) {
BX_DEBUG(("command complete %d", arg));
s.residue = s.data_len;
s.result = arg != 0;
if (s.packet) {
if (s.data_len == 0 && s.mode == USB_MSDM_DATAOUT) {
send_status();
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;
} else if (s.data_len == 0) {
s.mode = USB_MSDM_CSW;
}
return;
}
s.scsi_len = arg;
s.scsi_buf = s.scsi_dev->scsi_get_buf(tag);
if (p) {
copy_data();
if (s.usb_len == 0) {
BX_INFO(("packet complete %p", p));
s.packet = NULL;
}
}
}
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB

70
bochs/iodev/usb_msd.h Normal file
View File

@ -0,0 +1,70 @@
/////////////////////////////////////////////////////////////////////////
// $Id: usb_msd.h,v 1.1 2007-03-18 11:17:28 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2007 Volker Ruppert
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// USB mass storage device support ported from the Qemu project
#ifndef BX_IODEV_USB_MSD_H
#define BX_IODEV_USB_MSD_H
class scsi_device_t;
enum USBMSDMode {
USB_MSDM_CBW,
USB_MSDM_DATAOUT,
USB_MSDM_DATAIN,
USB_MSDM_CSW
};
typedef struct {
enum USBMSDMode mode;
Bit32u scsi_len;
Bit8u *scsi_buf;
Bit32u usb_len;
Bit8u *usb_buf;
Bit32u data_len;
Bit32u residue;
Bit32u tag;
int result;
device_image_t *hdimage;
scsi_device_t *scsi_dev;
USBPacket *packet;
} MSDState;
class usb_msd_device_t : public usb_device_t {
public:
usb_msd_device_t(void);
virtual ~usb_msd_device_t(void);
bx_bool init(const char *filename);
virtual void handle_reset();
virtual int handle_control(int request, int value, int index, int length, Bit8u *data);
virtual int handle_data(USBPacket *p);
protected:
void copy_data();
void send_status();
static void usb_msd_command_complete(void *this_ptr, int reason, Bit32u tag, Bit32u arg);
void command_complete(int reason, Bit32u tag, Bit32u arg);
private:
MSDState s;
};
#endif