168efb7710
connected device. For now this feature is only used by the 'disk' device to specify an alternative redolog filename of some image modes. - added new methods set_option() and timer() to the base class usb_device_c. The timer() method is periodicly called from the HC's frame timer code. - moved runtime device change stuff from the parameter handler to the end of timer() methods of all hubs. This makes sure that all parameters for the device have been set at connect time. TODO: this technique could also be used for the floppy and cdrom media change.
303 lines
13 KiB
C++
303 lines
13 KiB
C++
/////////////////////////////////////////////////////////////////////////
|
|
// $Id: usb_ohci.h,v 1.17 2011-01-16 12:46:48 vruppert Exp $
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2009 Benjamin D Lunt (fys at frontiernet net)
|
|
//
|
|
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef BX_IODEV_USB_OHCI_H
|
|
#define BX_IODEV_USB_OHCI_H
|
|
|
|
#if BX_USE_USB_OHCI_SMF
|
|
# define BX_OHCI_THIS theUSB_OHCI->
|
|
# define BX_OHCI_THIS_PTR theUSB_OHCI
|
|
#else
|
|
# define BX_OHCI_THIS this->
|
|
# define BX_OHCI_THIS_PTR this
|
|
#endif
|
|
|
|
// number of ports defined in bochs.h
|
|
|
|
#define OHCI_INTR_SO (1<<0) // Scheduling overrun
|
|
#define OHCI_INTR_WD (1<<1) // HcDoneHead writeback
|
|
#define OHCI_INTR_SF (1<<2) // Start of frame
|
|
#define OHCI_INTR_RD (1<<3) // Resume detect
|
|
#define OHCI_INTR_UE (1<<4) // Unrecoverable error
|
|
#define OHCI_INTR_FNO (1<<5) // Frame number overflow
|
|
#define OHCI_INTR_RHSC (1<<6) // Root hub status change
|
|
#define OHCI_INTR_OC (1<<30) // Ownership change
|
|
#define OHCI_INTR_MIE (1<<31) // Master Interrupt Enable
|
|
|
|
// Completion Codes
|
|
enum {
|
|
NoError = 0,
|
|
CRC,
|
|
BitStuffing,
|
|
DataToggleMismatch,
|
|
Stall,
|
|
DeviceNotResponding,
|
|
PIDCheckFailure,
|
|
UnexpectedPID,
|
|
DataOverrun,
|
|
DataUnderrun,
|
|
BufferOverrun = 0xC,
|
|
BufferUnderrun,
|
|
NotAccessed
|
|
};
|
|
|
|
|
|
#define ED_GET_MPS(x) (((x)->dword0 & 0x07FF0000) >> 16)
|
|
#define ED_GET_F(x) (((x)->dword0 & 0x00008000) >> 15)
|
|
#define ED_GET_K(x) (((x)->dword0 & 0x00004000) >> 14)
|
|
#define ED_GET_S(x) (((x)->dword0 & 0x00002000) >> 13)
|
|
#define ED_GET_D(x) (((x)->dword0 & 0x00001800) >> 11)
|
|
#define ED_GET_EN(x) (((x)->dword0 & 0x00000780) >> 7)
|
|
#define ED_GET_FA(x) (((x)->dword0 & 0x0000007F) >> 0)
|
|
#define ED_GET_TAILP(x) ((x)->dword1 & 0xFFFFFFF0)
|
|
#define ED_GET_HEADP(x) ((x)->dword2 & 0xFFFFFFF0)
|
|
#define ED_SET_HEADP(x, y) ((x)->dword2 = ((x)->dword2 & 0x0000000F) | ((y) & 0xFFFFFFF0))
|
|
#define ED_GET_C(x) (((x)->dword2 & 0x00000002) >> 1)
|
|
#define ED_SET_C(x,y) ((x)->dword2 = ((x)->dword2 & ~0x00000002) | ((y)<<1))
|
|
#define ED_GET_H(x) (((x)->dword2 & 0x00000001) >> 0)
|
|
#define ED_SET_H(x,y) ((x)->dword2 = ((x)->dword2 & ~0x00000001) | ((y)<<0))
|
|
#define ED_GET_NEXTED(x) ((x)->dword3 & 0xFFFFFFF0)
|
|
|
|
struct OHCI_ED {
|
|
Bit32u dword0;
|
|
Bit32u dword1;
|
|
Bit32u dword2;
|
|
Bit32u dword3;
|
|
};
|
|
|
|
|
|
#define TD_GET_R(x) (((x)->dword0 & 0x00040000) >> 18)
|
|
#define TD_GET_DP(x) (((x)->dword0 & 0x00180000) >> 19)
|
|
#define TD_GET_DI(x) (((x)->dword0 & 0x00E00000) >> 21)
|
|
#define TD_GET_T(x) (((x)->dword0 & 0x03000000) >> 24)
|
|
#define TD_SET_T(x,y) ((x)->dword0 = ((x)->dword0 & ~0x03000000) | ((y)<<24))
|
|
#define TD_GET_EC(x) (((x)->dword0 & 0x0C000000) >> 26)
|
|
#define TD_SET_EC(x,y) ((x)->dword0 = ((x)->dword0 & ~0x0C000000) | ((y)<<26))
|
|
#define TD_GET_CC(x) (((x)->dword0 & 0xF0000000) >> 28)
|
|
#define TD_SET_CC(x,y) ((x)->dword0 = ((x)->dword0 & ~0xF0000000) | ((y)<<28))
|
|
#define TD_GET_CBP(x) ((x)->dword1)
|
|
#define TD_SET_CBP(x,y) ((x)->dword1 = y)
|
|
#define TD_GET_NEXTTD(x) ((x)->dword2 & 0xFFFFFFF0)
|
|
#define TD_SET_NEXTTD(x,y) ((x)->dword2 = (y & 0xFFFFFFF0))
|
|
#define TD_GET_BE(x) ((x)->dword3)
|
|
|
|
struct OHCI_TD {
|
|
Bit32u dword0;
|
|
Bit32u dword1;
|
|
Bit32u dword2;
|
|
Bit32u dword3;
|
|
};
|
|
|
|
|
|
#define ISO_TD_GET_CC(x) (((x)->dword0 & 0xF0000000) >> 28)
|
|
#define ISO_TD_GET_FC(x) (((x)->dword0 & 0x0F000000) >> 24)
|
|
#define ISO_TD_GET_DI(x) (((x)->dword0 & 0x00E00000) >> 21)
|
|
#define ISO_TD_GET_SF(x) ((x)->dword0 & 0x0000FFFF)
|
|
#define ISO_TD_GET_BP0(x) (((x)->dword1 & 0xFFFFF000) >> 12)
|
|
#define ISO_TD_GET_NEXTTD(x) ((x)->dword2 & 0xFFFFFFF0)
|
|
#define ISO_TD_GET_BE(x) ((x)->dword3)
|
|
#define ISO_TD_GET_PSW0(x) ((x)->dword4 & 0x0000FFFF)
|
|
#define ISO_TD_GET_PSW1(x) (((x)->dword4 & 0xFFFF0000) >> 16)
|
|
#define ISO_TD_GET_PSW2(x) ((x)->dword5 & 0x0000FFFF)
|
|
#define ISO_TD_GET_PSW3(x) (((x)->dword5 & 0xFFFF0000) >> 16)
|
|
#define ISO_TD_GET_PSW4(x) ((x)->dword6 & 0x0000FFFF)
|
|
#define ISO_TD_GET_PSW5(x) (((x)->dword6 & 0xFFFF0000) >> 16)
|
|
#define ISO_TD_GET_PSW6(x) ((x)->dword7 & 0x0000FFFF)
|
|
#define ISO_TD_GET_PSW7(x) (((x)->dword7 & 0xFFFF0000) >> 16)
|
|
|
|
struct OHCI_ISO_TD {
|
|
Bit32u dword0;
|
|
Bit32u dword1;
|
|
Bit32u dword2;
|
|
Bit32u dword3;
|
|
Bit32u dword4;
|
|
Bit32u dword5;
|
|
Bit32u dword6;
|
|
Bit32u dword7;
|
|
};
|
|
|
|
|
|
typedef struct {
|
|
Bit32u base_addr;
|
|
|
|
int frame_index;
|
|
int interval_index;
|
|
|
|
struct OHCI_OP_REGS {
|
|
Bit16u HcRevision;
|
|
struct {
|
|
Bit32u reserved; // 21 bit reserved = 0x000000 R R
|
|
bx_bool rwe; // 1 bit RemoteWakeupEnable = 0b RW R
|
|
bx_bool rwc; // 1 bit RemoteWakeupConnected = 0b RW RW
|
|
bx_bool ir; // 1 bit InterruptRouting = 0b RW R
|
|
Bit8u hcfs; // 2 bit HostControllerFuncState = 00b RW RW
|
|
bx_bool ble; // 1 bit BulkListEnable = 0b RW R
|
|
bx_bool cle; // 1 bit ControlListEnable = 0b RW R
|
|
bx_bool ie; // 1 bit IsochronousEnable = 0b RW R
|
|
bx_bool ple; // 1 bit PeriodicListEnable = 0b RW R
|
|
Bit8u cbsr; // 2 bit ControlBulkService Ratio = 00b RW R
|
|
} HcControl; // = 0x00000000
|
|
struct {
|
|
Bit16u reserved0; // 14 bit reserved = 0x000000 R R
|
|
Bit8u soc; // 2 bit SchedulingOverrunCount = 00b R RW
|
|
Bit16u reserved1; // 12 bit reserved = 0x000000 R R
|
|
bx_bool ocr; // 1 bit OwnershipChangeRequest = 0b RW RW
|
|
bx_bool blf; // 1 bit BulkListFilled = 0b RW RW
|
|
bx_bool clf; // 1 bit ControlListFilled = 0b RW RW
|
|
bx_bool hcr; // 1 bit HostControllerReset = 0b RW RW
|
|
} HcCommandStatus; // = 0x00000000
|
|
Bit32u HcInterruptStatus;
|
|
Bit32u HcInterruptEnable;
|
|
Bit32u HcHCCA;
|
|
Bit32u HcPeriodCurrentED;
|
|
Bit32u HcControlHeadED;
|
|
Bit32u HcControlCurrentED;
|
|
Bit32u HcBulkHeadED;
|
|
Bit32u HcBulkCurrentED;
|
|
Bit32u HcDoneHead;
|
|
struct {
|
|
bx_bool fit; // 1 bit FrameIntervalToggle = 0b RW R
|
|
Bit16u fsmps; // 15 bit FSLargestDataPacket = TBD (0) RW R
|
|
Bit8u reserved; // 2 bit reserved = 00b R R
|
|
Bit16u fi; // 14 bit FrameInterval = 0x2EDF RW R
|
|
} HcFmInterval; // = 0x00002EDF
|
|
bx_bool HcFmRemainingToggle; // 1 bit FrameRemainingToggle = 0b R RW
|
|
Bit32u HcFmNumber;
|
|
Bit32u HcPeriodicStart;
|
|
Bit16u HcLSThreshold;
|
|
struct {
|
|
Bit8u potpgt; // 8 bit PowerOnToPowerGoodTime = 0x10 RW R
|
|
Bit16u reserved; // 11 bit reserved = 0x000 R R
|
|
bx_bool nocp; // 1 bit NoOverCurrentProtection = 0b RW R
|
|
bx_bool ocpm; // 1 bit OverCurrentProtectionMode = 1b RW R
|
|
bx_bool dt; // 1 bit DeviceType = 0b R R
|
|
bx_bool nps; // 1 bit NoPowerSwitching = 0b RW R
|
|
bx_bool psm; // 1 bit PowerSwitchingMode = 1b RW R
|
|
Bit8u ndp; // 8 bit NumberDownstreamPorts = NUMPORTS RW R
|
|
} HcRhDescriptorA; // = 0x100009xx
|
|
struct {
|
|
Bit16u ppcm; // 16 bit PortPowerControlMask = 0x0002 RW R
|
|
Bit16u dr; // 16 bit DeviceRemovable = 0x0000 RW R
|
|
} HcRhDescriptorB; // = 0x00020000
|
|
struct {
|
|
bx_bool crwe; // 1 bit ClearRemoteWakeupEnable = 0b WC R
|
|
Bit16u reserved0; // 13 bit reserved = 0x000000 R R
|
|
bx_bool ocic; // 1 bit OverCurrentIndicatorChange = 0b RW RW
|
|
bx_bool lpsc; // 1 bit LocalPowerStatusChange(r) = 0b RW R
|
|
bx_bool drwe; // 1 bit DeviceRemoteWakeupEnable(r) = 0b RW R
|
|
Bit16u reserved1; // 13 bit reserved = 0x000000 R R
|
|
bx_bool oci; // 1 bit OverCurrentIndicator = 0b R RW
|
|
bx_bool lps; // 1 bit LocalPowerStatus(r) = 0b RW R
|
|
} HcRhStatus; // = 0x00000000
|
|
} op_regs;
|
|
|
|
struct {
|
|
// our data
|
|
usb_device_c *device; // device connected to this port
|
|
|
|
struct {
|
|
Bit16u reserved0; // 11 bit reserved = 0x000000 R R
|
|
bx_bool prsc; // 1 bit PortResetStatusChange = 0b RW RW
|
|
bx_bool ocic; // 1 bit OverCurrentIndicatorChange = 0b RW RW
|
|
bx_bool pssc; // 1 bit PortSuspendStatusChange = 0b RW RW
|
|
bx_bool pesc; // 1 bit PortEnableStatusChange = 0b RW RW
|
|
bx_bool csc; // 1 bit ConnectStatusChange = 0b RW RW
|
|
Bit8u reserved1; // 6 bit reserved = 0x00 R R
|
|
bx_bool lsda; // 1 bit LowSpeedDeviceAttached = 0b RW RW
|
|
bx_bool pps; // 1 bit PortPowerStatus = 0b RW RW
|
|
Bit8u reserved2; // 3 bit reserved = 0x0 R R
|
|
bx_bool prs; // 1 bit PortResetStatus = 0b RW RW
|
|
bx_bool poci; // 1 bit PortOverCurrentIndicator = 0b RW RW
|
|
bx_bool pss; // 1 bit PortSuspendStatus = 0b RW RW
|
|
bx_bool pes; // 1 bit PortEnableStatus = 0b RW RW
|
|
bx_bool ccs; // 1 bit CurrentConnectStatus = 0b RW RW
|
|
} HcRhPortStatus;
|
|
} usb_port[BX_N_USB_OHCI_PORTS];
|
|
|
|
Bit8u pci_conf[256];
|
|
Bit8u devfunc;
|
|
unsigned ohci_done_count;
|
|
bx_bool use_control_head;
|
|
bx_bool use_bulk_head;
|
|
Bit64u sof_time;
|
|
|
|
int statusbar_id; // ID of the status LEDs
|
|
int iolight_counter;
|
|
int iolight_timer_index;
|
|
Bit8u device_change;
|
|
} bx_usb_ohci_t;
|
|
|
|
|
|
|
|
class bx_usb_ohci_c : public bx_devmodel_c, public bx_pci_device_stub_c {
|
|
public:
|
|
bx_usb_ohci_c();
|
|
virtual ~bx_usb_ohci_c();
|
|
virtual void init(void);
|
|
virtual void reset(unsigned);
|
|
virtual void register_state(void);
|
|
virtual void after_restore_state(void);
|
|
virtual Bit32u pci_read_handler(Bit8u address, unsigned io_len);
|
|
virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len);
|
|
|
|
static const char *usb_param_handler(bx_param_string_c *param, int set,
|
|
const char *oldval, const char *val, int maxlen);
|
|
|
|
private:
|
|
|
|
bx_usb_ohci_t hub;
|
|
Bit8u *device_buffer;
|
|
|
|
USBPacket usb_packet;
|
|
|
|
static void reset_hc();
|
|
static void reset_port(int);
|
|
static void update_irq();
|
|
static void set_interrupt(Bit32u value);
|
|
|
|
static void init_device(Bit8u port, bx_list_c *portconf);
|
|
static void remove_device(Bit8u port);
|
|
static int broadcast_packet(USBPacket *p);
|
|
static void usb_set_connect_status(Bit8u port, int type, bx_bool connected);
|
|
|
|
static void usb_frame_handler(void *);
|
|
void usb_frame_timer(void);
|
|
|
|
static Bit32u get_frame_remaining(void);
|
|
|
|
void process_ed(struct OHCI_ED *, const Bit32u);
|
|
bx_bool process_td(struct OHCI_TD *, struct OHCI_ED *);
|
|
|
|
#if BX_USE_USB_OHCI_SMF
|
|
static bx_bool read_handler(bx_phy_address addr, unsigned len, void *data, void *param);
|
|
static bx_bool write_handler(bx_phy_address addr, unsigned len, void *data, void *param);
|
|
#else
|
|
bx_bool read_handler(bx_phy_address addr, unsigned len, void *data, void *param);
|
|
bx_bool write_handler(bx_phy_address addr, unsigned len, void *data, void *param);
|
|
#endif
|
|
|
|
static void iolight_timer_handler(void *);
|
|
void iolight_timer(void);
|
|
|
|
};
|
|
|
|
#endif // BX_IODEV_USB_OHCI_H
|