- 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:
parent
e39769a7e8
commit
a70cc33578
@ -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],
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
510
bochs/iodev/usb_msd.cc
Normal 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
70
bochs/iodev/usb_msd.h
Normal 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
|
Loading…
Reference in New Issue
Block a user