- preparing USB cdrom support (not yet complete)

* added cdrom support in the usb_msd code (already present in the SCSI code)
  * added code for deferring packets in usb_msd and the common USB code (TODO:
    cancel packets by the host controller)
  * added SCSI cdrom drive lock flag
- clean up SCSI request queues in destructor
- changed type of cdrom path/device parameter to const char
- moved the shared init device code to a common function
- reset hub count if the last external hub has been removed
This commit is contained in:
Volker Ruppert 2009-03-09 12:18:40 +00:00
parent 9024d7b202
commit 9549d7ece6
11 changed files with 167 additions and 123 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cdrom.cc,v 1.95 2009-02-08 09:05:52 vruppert Exp $
// $Id: cdrom.cc,v 1.96 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -501,7 +501,7 @@ int GetCDCapacity(unsigned int hid, unsigned int tid, unsigned int lun)
#endif
cdrom_interface::cdrom_interface(char *dev)
cdrom_interface::cdrom_interface(const char *dev)
{
put("CD");
fd = -1; // File descriptor not yet allocated
@ -522,7 +522,7 @@ cdrom_interface::cdrom_interface(char *dev)
void
cdrom_interface::init(void) {
BX_DEBUG(("Init $Id: cdrom.cc,v 1.95 2009-02-08 09:05:52 vruppert Exp $"));
BX_DEBUG(("Init $Id: cdrom.cc,v 1.96 2009-03-09 12:18:40 vruppert Exp $"));
BX_INFO(("file = '%s'",path));
}
@ -539,7 +539,7 @@ cdrom_interface::~cdrom_interface(void)
}
bx_bool
cdrom_interface::insert_cdrom(char *dev)
cdrom_interface::insert_cdrom(const char *dev)
{
unsigned char buffer[BX_CD_FRAMESIZE];
#ifndef WIN32

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cdrom.h,v 1.22 2009-02-08 09:05:52 vruppert Exp $
// $Id: cdrom.h,v 1.23 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -30,12 +30,12 @@
class cdrom_interface : public logfunctions {
public:
cdrom_interface(char *dev);
cdrom_interface(const char *dev);
virtual ~cdrom_interface(void);
void init(void);
// Load CD-ROM. Returns 0 if CD is not ready.
bx_bool insert_cdrom(char *dev = NULL);
bx_bool insert_cdrom(const char *dev = NULL);
// Logically eject the CD.
void eject_cdrom();

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: scsi_device.cc,v 1.10 2009-02-08 09:05:52 vruppert Exp $
// $Id: scsi_device.cc,v 1.11 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2007 Volker Ruppert
@ -48,6 +48,7 @@ scsi_device_t::scsi_device_t(device_image_t *_hdimage, int _tcq,
completion = _completion;
dev = _dev;
cluster_size = 1;
locked = 0;
put("SCSID");
}
@ -64,12 +65,32 @@ scsi_device_t::scsi_device_t(LOWLEVEL_CDROM *_cdrom, int _tcq,
completion = _completion;
dev = _dev;
cluster_size = 4;
locked = 0;
put("SCSIC");
}
scsi_device_t::~scsi_device_t(void)
{
SCSIRequest *r, *next;
if (requests) {
r = requests;
while (r != NULL) {
next = r->next;
delete r;
r = next;
}
}
if (free_requests) {
r = free_requests;
while (r != NULL) {
next = r->next;
delete r;
r = next;
}
free_requests = NULL;
}
}
void scsi_device_t::register_state(bx_list_c *parent, const char *name)
@ -422,7 +443,7 @@ Bit32s scsi_device_t::scsi_send_command(Bit32u tag, Bit8u *buf, int lun)
p[5] = 0xff; /* CD DA, DA accurate, RW supported,
RW corrected, C2 errors, ISRC,
UPC, Bar code */
p[6] = 0x2d; // TODO: | (bdrv_is_locked(s->bdrv)? 2 : 0);
p[6] = 0x2d | (locked ? 2 : 0);
/* Locking supported, jumper present, eject, tray */
p[7] = 0; /* no volume & mute control, no changer */
p[8] = (50 * 176) >> 8; // 50x read speed
@ -450,6 +471,7 @@ Bit32s scsi_device_t::scsi_send_command(Bit32u tag, Bit8u *buf, int lun)
break;
case 0x1e:
BX_INFO(("Prevent Allow Medium Removal (prevent = %d)", buf[4] & 3));
locked = buf[4] & 1;
break;
case 0x25:
BX_DEBUG(("Read Capacity"));

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: scsi_device.h,v 1.7 2009-02-08 09:05:52 vruppert Exp $
// $Id: scsi_device.h,v 1.8 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2007 Volker Ruppert
@ -88,6 +88,7 @@ private:
int tcq;
scsi_completionfn completion;
void *dev;
bx_bool locked;
};
#endif

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: usb_common.cc,v 1.6 2009-03-01 19:29:36 vruppert Exp $
// $Id: usb_common.cc,v 1.7 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2009 Benjamin D Lunt (fys at frontiernet net)
@ -55,10 +55,49 @@
#include "usb_common.h"
#include "usb_hid.h"
#include "usb_hub.h"
#include "usb_msd.h"
#define LOG_THIS
usbdev_type usb_init_device(const char *devname, logfunctions *hub, usb_device_c **device)
{
usbdev_type type = USB_DEV_TYPE_NONE;
if (!strcmp(devname, "mouse")) {
type = USB_DEV_TYPE_MOUSE;
*device = new usb_hid_device_c(type);
} else if (!strcmp(devname, "tablet")) {
type = USB_DEV_TYPE_TABLET;
*device = new usb_hid_device_c(type);
} else if (!strcmp(devname, "keypad")) {
type = USB_DEV_TYPE_KEYPAD;
*device = new usb_hid_device_c(type);
} else if (!strncmp(devname, "disk", 4)) {
if ((strlen(devname) > 5) && (devname[4] == ':')) {
type = USB_DEV_TYPE_DISK;
*device = new usb_msd_device_c(type, devname+5);
} else {
hub->panic("USB device 'disk' needs a filename separated with a colon");
return type;
}
// } else if (!strncmp(devname, "cdrom", 5)) {
// if ((strlen(devname) > 6) && (devname[5] == ':')) {
// type = USB_DEV_TYPE_CDROM;
// *device = new usb_msd_device_c(type, devname+6);
// } else {
// hub->panic("USB device 'cdrom' needs a filename separated with a colon");
// return type;
// }
} else if (!strcmp(devname, "hub")) {
type = USB_DEV_TYPE_HUB;
*device = new usb_hub_device_c();
} else {
hub->panic("unknown USB device: %s", devname);
return type;
}
return type;
}
// Dumps the contents of a buffer to the log file
void usb_device_c::usb_dump_packet(Bit8u *data, unsigned size)

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: usb_common.h,v 1.7 2009-03-07 16:57:17 vruppert Exp $
// $Id: usb_common.h,v 1.8 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2009 Benjamin D Lunt (fys at frontiernet net)
@ -105,12 +105,15 @@
#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_DT_INTERFACE_POWER 0x08
class usb_device_c;
struct USBPacket {
int pid;
Bit8u devaddr;
Bit8u devep;
Bit8u *data;
int len;
usb_device_c *dev;
};
enum usbdev_type {
@ -119,9 +122,12 @@ enum usbdev_type {
USB_DEV_TYPE_TABLET,
USB_DEV_TYPE_KEYPAD,
USB_DEV_TYPE_DISK,
USB_DEV_TYPE_CDROM,
USB_DEV_TYPE_HUB
};
usbdev_type usb_init_device(const char *devname, logfunctions *hc, usb_device_c **device);
class usb_device_c : public logfunctions {
public:
@ -135,6 +141,7 @@ public:
void register_state(bx_list_c *parent);
virtual void register_state_specific(bx_list_c *parent) {}
virtual void after_restore_state() {}
virtual void cancel_packet(USBPacket *p) {}
bx_bool get_connected() {return d.connected;}
usbdev_type get_type() {return d.type;}
@ -165,4 +172,14 @@ protected:
int set_usb_string(Bit8u *buf, const char *str);
};
static inline void usb_defer_packet(USBPacket *p, usb_device_c *dev)
{
p->dev = dev;
}
static inline void usb_cancel_packet(USBPacket *p)
{
p->dev->cancel_packet(p);
}
#endif

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: usb_hub.cc,v 1.1 2009-03-07 16:57:17 vruppert Exp $
// $Id: usb_hub.cc,v 1.2 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2009 Volker Ruppert
@ -207,6 +207,9 @@ static bx_bool remove_usb_hub(usb_hub_device_c *hub)
prev->next = ext_usb_hub->next;
}
free(ext_usb_hub);
if (ext_usb_hubs == NULL) {
hub_count = 0;
}
return 1;
} else {
prev = ext_usb_hub;
@ -598,7 +601,7 @@ int usb_hub_device_c::handle_packet(USBPacket *p)
void usb_hub_device_c::init_device(Bit8u port, const char *devname)
{
usbdev_type type = USB_DEV_TYPE_NONE;
usbdev_type type;
char pname[BX_PATHNAME_LEN];
if (!strlen(devname) || !strcmp(devname, "none")) return;
@ -607,35 +610,13 @@ void usb_hub_device_c::init_device(Bit8u port, const char *devname)
BX_ERROR(("init_device(): port%d already in use", port+1));
return;
}
if (!strcmp(devname, "mouse")) {
type = USB_DEV_TYPE_MOUSE;
hub.usb_port[port].device = new usb_hid_device_c(type);
} else if (!strcmp(devname, "tablet")) {
type = USB_DEV_TYPE_TABLET;
hub.usb_port[port].device = new usb_hid_device_c(type);
} else if (!strcmp(devname, "keypad")) {
type = USB_DEV_TYPE_KEYPAD;
hub.usb_port[port].device = new usb_hid_device_c(type);
} else if (!strncmp(devname, "disk", 4)) {
if ((strlen(devname) > 5) && (devname[4] == ':')) {
type = USB_DEV_TYPE_DISK;
hub.usb_port[port].device = new usb_msd_device_c(devname+5);
} else {
BX_PANIC(("USB device 'disk' needs a filename separated with a colon"));
return;
}
} else if (!strcmp(devname, "hub")) {
type = USB_DEV_TYPE_HUB;
hub.usb_port[port].device = new usb_hub_device_c();
} else {
BX_PANIC(("unknown USB device: %s", devname));
return;
type = usb_init_device(devname, this, &hub.usb_port[port].device);
if (hub.usb_port[port].device != NULL) {
sprintf(pname, "port%d.device", port+1);
bx_list_c *devlist = (bx_list_c*)SIM->get_param(pname, hub.state);
hub.usb_port[port].device->register_state(devlist);
usb_set_connect_status(port, type, 1);
}
sprintf(pname, "port%d.device", port+1);
bx_list_c *devlist = (bx_list_c*)SIM->get_param(pname, hub.state);
hub.usb_port[port].device->register_state(devlist);
usb_set_connect_status(port, type, 1);
}
void usb_hub_device_c::remove_device(Bit8u port)

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: usb_msd.cc,v 1.17 2009-03-01 19:29:36 vruppert Exp $
// $Id: usb_msd.cc,v 1.18 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2009 Volker Ruppert
@ -31,6 +31,7 @@
#if BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB
#include "usb_common.h"
#include "cdrom.h"
#include "hdimage.h"
#include "scsi_device.h"
#include "usb_msd.h"
@ -130,11 +131,15 @@ static const Bit8u bx_msd_config_descriptor[] = {
0x00 /* u8 ep_bInterval; */
};
usb_msd_device_c::usb_msd_device_c(const char *filename)
usb_msd_device_c::usb_msd_device_c(usbdev_type type, const char *filename)
{
d.type = USB_DEV_TYPE_DISK;
d.type = type;
d.speed = USB_SPEED_FULL;
strcpy(d.devname, "BOCHS USB HARDDRIVE");
if (d.type == USB_DEV_TYPE_DISK) {
strcpy(d.devname, "BOCHS USB HARDDRIVE");
} else if (d.type == USB_DEV_TYPE_CDROM) {
strcpy(d.devname, "BOCHS USB CDROM");
}
memset((void*)&s, 0, sizeof(s));
s.fname = filename;
@ -145,23 +150,36 @@ usb_msd_device_c::~usb_msd_device_c(void)
{
if (s.scsi_dev != NULL)
delete s.scsi_dev;
s.hdimage->close();
delete s.hdimage;
if (s.hdimage != NULL) {
delete s.hdimage;
} else if (s.cdrom != NULL) {
delete s.cdrom;
}
}
bx_bool usb_msd_device_c::init()
{
s.hdimage = new default_image_t();
if (s.hdimage->open(s.fname) < 0) {
BX_ERROR(("could not open hard drive image file '%s'", s.fname));
return 0;
} else {
s.scsi_dev = new scsi_device_t(s.hdimage, 0, usb_msd_command_complete, (void*)this);
s.scsi_dev->register_state(s.sr_list, "scsidev");
s.mode = USB_MSDM_CBW;
d.connected = 1;
return 1;
if (d.type == USB_DEV_TYPE_DISK) {
s.hdimage = new default_image_t();
if (s.hdimage->open(s.fname) < 0) {
BX_ERROR(("could not open hard drive image file '%s'", s.fname));
return 0;
} else {
s.scsi_dev = new scsi_device_t(s.hdimage, 0, usb_msd_command_complete, (void*)this);
}
} else if (d.type == USB_DEV_TYPE_CDROM) {
s.cdrom = new LOWLEVEL_CDROM(s.fname);
if (!s.cdrom->insert_cdrom()) {
BX_ERROR(("could not open cdrom image file '%s'", s.fname));
return 0;
} else {
s.scsi_dev = new scsi_device_t(s.cdrom, 0, usb_msd_command_complete, (void*)this);
}
}
s.scsi_dev->register_state(s.sr_list, "scsidev");
s.mode = USB_MSDM_CBW;
d.connected = 1;
return 1;
}
void usb_msd_device_c::register_state_specific(bx_list_c *parent)
@ -375,7 +393,7 @@ int usb_msd_device_c::handle_data(USBPacket *p)
}
if (s.usb_len) {
BX_INFO(("deferring packet %p", p));
// TODO: defer packet
usb_defer_packet(p, this);
s.packet = p;
ret = USB_RET_ASYNC;
} else {
@ -397,7 +415,7 @@ int usb_msd_device_c::handle_data(USBPacket *p)
case USB_MSDM_DATAOUT:
if (s.data_len != 0 || len < 13)
goto fail;
// TODO: defer packet
usb_defer_packet(p, this);
s.packet = p;
ret = USB_RET_ASYNC;
break;
@ -433,7 +451,7 @@ int usb_msd_device_c::handle_data(USBPacket *p)
}
if (s.usb_len) {
BX_INFO(("deferring packet %p", p));
// TODO: defer packet
usb_defer_packet(p, this);
s.packet = p;
ret = USB_RET_ASYNC;
} else {
@ -541,4 +559,11 @@ void usb_msd_device_c::command_complete(int reason, Bit32u tag, Bit32u arg)
}
}
void usb_msd_device_c::cancel_packet(USBPacket *p)
{
s.scsi_dev->scsi_cancel_io(s.tag);
s.packet = NULL;
s.scsi_len = 0;
}
#endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: usb_msd.h,v 1.11 2009-03-01 19:29:36 vruppert Exp $
// $Id: usb_msd.h,v 1.12 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2009 Volker Ruppert
@ -25,11 +25,12 @@
#define BX_IODEV_USB_MSD_H
class device_image_t;
class LOWLEVEL_CDROM;
class scsi_device_t;
class usb_msd_device_c : public usb_device_c {
public:
usb_msd_device_c(const char *filename);
usb_msd_device_c(usbdev_type type, const char *filename);
virtual ~usb_msd_device_c(void);
bx_bool init();
@ -38,6 +39,7 @@ public:
virtual int handle_control(int request, int value, int index, int length, Bit8u *data);
virtual int handle_data(USBPacket *p);
virtual void register_state_specific(bx_list_c *parent);
virtual void cancel_packet(USBPacket *p);
protected:
void copy_data();
@ -57,6 +59,7 @@ private:
Bit32u tag;
int result;
device_image_t *hdimage;
LOWLEVEL_CDROM *cdrom;
scsi_device_t *scsi_dev;
USBPacket *packet;
bx_list_c *sr_list;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: usb_ohci.cc,v 1.18 2009-03-07 16:57:17 vruppert Exp $
// $Id: usb_ohci.cc,v 1.19 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2009 Benjamin D Lunt (fys at frontiernet net)
@ -453,7 +453,7 @@ void bx_usb_ohci_c::after_restore_state(void)
void bx_usb_ohci_c::init_device(Bit8u port, const char *devname)
{
usbdev_type type = USB_DEV_TYPE_NONE;
usbdev_type type;
char pname[BX_PATHNAME_LEN];
if (!strlen(devname) || !strcmp(devname, "none")) return;
@ -462,35 +462,13 @@ void bx_usb_ohci_c::init_device(Bit8u port, const char *devname)
BX_ERROR(("init_device(): port%d already in use", port+1));
return;
}
if (!strcmp(devname, "mouse")) {
type = USB_DEV_TYPE_MOUSE;
BX_OHCI_THIS hub.usb_port[port].device = new usb_hid_device_c(type);
} else if (!strcmp(devname, "tablet")) {
type = USB_DEV_TYPE_TABLET;
BX_OHCI_THIS hub.usb_port[port].device = new usb_hid_device_c(type);
} else if (!strcmp(devname, "keypad")) {
type = USB_DEV_TYPE_KEYPAD;
BX_OHCI_THIS hub.usb_port[port].device = new usb_hid_device_c(type);
} else if (!strncmp(devname, "disk", 4)) {
if ((strlen(devname) > 5) && (devname[4] == ':')) {
type = USB_DEV_TYPE_DISK;
BX_OHCI_THIS hub.usb_port[port].device = new usb_msd_device_c(devname+5);
} else {
BX_PANIC(("USB device 'disk' needs a filename separated with a colon"));
return;
}
} else if (!strcmp(devname, "hub")) {
type = USB_DEV_TYPE_HUB;
BX_OHCI_THIS hub.usb_port[port].device = new usb_hub_device_c();
} else {
BX_PANIC(("unknown USB device: %s", devname));
return;
type = usb_init_device(devname, BX_OHCI_THIS_PTR, &BX_OHCI_THIS hub.usb_port[port].device);
if (BX_OHCI_THIS hub.usb_port[port].device != NULL) {
sprintf(pname, "usb_ohci.hub.port%d.device", port+1);
bx_list_c *devlist = (bx_list_c*)SIM->get_param(pname, SIM->get_bochs_root());
BX_OHCI_THIS hub.usb_port[port].device->register_state(devlist);
usb_set_connect_status(port, type, 1);
}
sprintf(pname, "usb_ohci.hub.port%d.device", port+1);
bx_list_c *devlist = (bx_list_c*)SIM->get_param(pname, SIM->get_bochs_root());
BX_OHCI_THIS hub.usb_port[port].device->register_state(devlist);
usb_set_connect_status(port, type, 1);
}
void bx_usb_ohci_c::remove_device(Bit8u port)

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: usb_uhci.cc,v 1.15 2009-03-07 16:57:17 vruppert Exp $
// $Id: usb_uhci.cc,v 1.16 2009-03-09 12:18:40 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2009 Benjamin D Lunt (fys at frontiernet net)
@ -283,7 +283,7 @@ void bx_usb_uhci_c::after_restore_state(void)
void bx_usb_uhci_c::init_device(Bit8u port, const char *devname)
{
usbdev_type type = USB_DEV_TYPE_NONE;
usbdev_type type;
char pname[BX_PATHNAME_LEN];
if (!strlen(devname) || !strcmp(devname, "none")) return;
@ -292,35 +292,13 @@ void bx_usb_uhci_c::init_device(Bit8u port, const char *devname)
BX_ERROR(("init_device(): port%d already in use", port+1));
return;
}
if (!strcmp(devname, "mouse")) {
type = USB_DEV_TYPE_MOUSE;
BX_UHCI_THIS hub.usb_port[port].device = new usb_hid_device_c(type);
} else if (!strcmp(devname, "tablet")) {
type = USB_DEV_TYPE_TABLET;
BX_UHCI_THIS hub.usb_port[port].device = new usb_hid_device_c(type);
} else if (!strcmp(devname, "keypad")) {
type = USB_DEV_TYPE_KEYPAD;
BX_UHCI_THIS hub.usb_port[port].device = new usb_hid_device_c(type);
} else if (!strncmp(devname, "disk", 4)) {
if ((strlen(devname) > 5) && (devname[4] == ':')) {
type = USB_DEV_TYPE_DISK;
BX_UHCI_THIS hub.usb_port[port].device = new usb_msd_device_c(devname+5);
} else {
BX_PANIC(("USB device 'disk' needs a filename separated with a colon"));
return;
}
} else if (!strcmp(devname, "hub")) {
type = USB_DEV_TYPE_HUB;
BX_UHCI_THIS hub.usb_port[port].device = new usb_hub_device_c();
} else {
BX_PANIC(("unknown USB device: %s", devname));
return;
type = usb_init_device(devname, BX_UHCI_THIS_PTR, &BX_UHCI_THIS hub.usb_port[port].device);
if (BX_UHCI_THIS hub.usb_port[port].device != NULL) {
sprintf(pname, "usb_uhci.hub.port%d.device", port+1);
bx_list_c *devlist = (bx_list_c*)SIM->get_param(pname, SIM->get_bochs_root());
BX_UHCI_THIS hub.usb_port[port].device->register_state(devlist);
usb_set_connect_status(port, type, 1);
}
sprintf(pname, "usb_uhci.hub.port%d.device", port+1);
bx_list_c *devlist = (bx_list_c*)SIM->get_param(pname, SIM->get_bochs_root());
BX_UHCI_THIS hub.usb_port[port].device->register_state(devlist);
usb_set_connect_status(port, type, 1);
}
void bx_usb_uhci_c::remove_device(Bit8u port)