1 ///////////////////////////////////////////////////////////////////////// 2 // $Id: usb_ohci.h 14158 2021-02-20 19:58:39Z vruppert $ 3 ///////////////////////////////////////////////////////////////////////// 4 // 5 // Copyright (C) 2009-2016 Benjamin D Lunt (fys [at] fysnet [dot] net) 6 // 2009-2021 The Bochs Project 7 // 8 // This library is free software; you can redistribute it and/or 9 // modify it under the terms of the GNU Lesser General Public 10 // License as published by the Free Software Foundation; either 11 // version 2 of the License, or (at your option) any later version. 12 // 13 // This library is distributed in the hope that it will be useful, 14 // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 // Lesser General Public License for more details. 17 // 18 // You should have received a copy of the GNU Lesser General Public 19 // License along with this library; if not, write to the Free Software 20 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 ///////////////////////////////////////////////////////////////////////// 22 23 #ifndef BX_IODEV_USB_OHCI_H 24 #define BX_IODEV_USB_OHCI_H 25 26 #if BX_USE_USB_OHCI_SMF 27 # define BX_OHCI_THIS theUSB_OHCI-> 28 # define BX_OHCI_THIS_PTR theUSB_OHCI 29 #else 30 # define BX_OHCI_THIS this-> 31 # define BX_OHCI_THIS_PTR this 32 #endif 33 34 #define USB_OHCI_PORTS 2 35 36 // HCFS values 37 #define OHCI_USB_RESET 0x00 38 #define OHCI_USB_RESUME 0x01 39 #define OHCI_USB_OPERATIONAL 0x02 40 #define OHCI_USB_SUSPEND 0x03 41 42 #define OHCI_INTR_SO (1<<0) // Scheduling overrun 43 #define OHCI_INTR_WD (1<<1) // HcDoneHead writeback 44 #define OHCI_INTR_SF (1<<2) // Start of frame 45 #define OHCI_INTR_RD (1<<3) // Resume detect 46 #define OHCI_INTR_UE (1<<4) // Unrecoverable error 47 #define OHCI_INTR_FNO (1<<5) // Frame number overflow 48 #define OHCI_INTR_RHSC (1<<6) // Root hub status change 49 #define OHCI_INTR_OC (1<<30) // Ownership change 50 #define OHCI_INTR_MIE (1<<31) // Master Interrupt Enable 51 52 // Completion Codes 53 enum { 54 NoError = 0, 55 CRC, 56 BitStuffing, 57 DataToggleMismatch, 58 Stall, 59 DeviceNotResponding, 60 PIDCheckFailure, 61 UnexpectedPID, 62 DataOverrun, 63 DataUnderrun, 64 BufferOverrun = 0xC, 65 BufferUnderrun, 66 NotAccessed 67 }; 68 69 70 #define ED_GET_MPS(x) (((x)->dword0 & 0x07FF0000) >> 16) 71 #define ED_GET_F(x) (((x)->dword0 & 0x00008000) >> 15) 72 #define ED_GET_K(x) (((x)->dword0 & 0x00004000) >> 14) 73 #define ED_GET_S(x) (((x)->dword0 & 0x00002000) >> 13) 74 #define ED_GET_D(x) (((x)->dword0 & 0x00001800) >> 11) 75 #define ED_GET_EN(x) (((x)->dword0 & 0x00000780) >> 7) 76 #define ED_GET_FA(x) (((x)->dword0 & 0x0000007F) >> 0) 77 #define ED_GET_TAILP(x) ((x)->dword1 & 0xFFFFFFF0) 78 #define ED_GET_HEADP(x) ((x)->dword2 & 0xFFFFFFF0) 79 #define ED_SET_HEADP(x, y) ((x)->dword2 = ((x)->dword2 & 0x0000000F) | ((y) & 0xFFFFFFF0)) 80 #define ED_GET_C(x) (((x)->dword2 & 0x00000002) >> 1) 81 #define ED_SET_C(x,y) ((x)->dword2 = ((x)->dword2 & ~0x00000002) | ((y)<<1)) 82 #define ED_GET_H(x) (((x)->dword2 & 0x00000001) >> 0) 83 #define ED_SET_H(x,y) ((x)->dword2 = ((x)->dword2 & ~0x00000001) | ((y)<<0)) 84 #define ED_GET_NEXTED(x) ((x)->dword3 & 0xFFFFFFF0) 85 86 struct OHCI_ED { 87 Bit32u dword0; 88 Bit32u dword1; 89 Bit32u dword2; 90 Bit32u dword3; 91 }; 92 93 94 #define TD_GET_R(x) (((x)->dword0 & 0x00040000) >> 18) 95 #define TD_GET_DP(x) (((x)->dword0 & 0x00180000) >> 19) 96 #define TD_GET_DI(x) (((x)->dword0 & 0x00E00000) >> 21) 97 #define TD_GET_T(x) (((x)->dword0 & 0x03000000) >> 24) 98 #define TD_SET_T(x,y) ((x)->dword0 = ((x)->dword0 & ~0x03000000) | ((y)<<24)) 99 #define TD_GET_EC(x) (((x)->dword0 & 0x0C000000) >> 26) 100 #define TD_SET_EC(x,y) ((x)->dword0 = ((x)->dword0 & ~0x0C000000) | ((y)<<26)) 101 #define TD_GET_CC(x) (((x)->dword0 & 0xF0000000) >> 28) 102 #define TD_SET_CC(x,y) ((x)->dword0 = ((x)->dword0 & ~0xF0000000) | ((y)<<28)) 103 #define TD_GET_CBP(x) ((x)->dword1) 104 #define TD_SET_CBP(x,y) ((x)->dword1 = y) 105 #define TD_GET_NEXTTD(x) ((x)->dword2 & 0xFFFFFFF0) 106 #define TD_SET_NEXTTD(x,y) ((x)->dword2 = (y & 0xFFFFFFF0)) 107 #define TD_GET_BE(x) ((x)->dword3) 108 109 struct OHCI_TD { 110 Bit32u dword0; 111 Bit32u dword1; 112 Bit32u dword2; 113 Bit32u dword3; 114 }; 115 116 117 #define ISO_TD_GET_CC(x) (((x)->dword0 & 0xF0000000) >> 28) 118 #define ISO_TD_GET_FC(x) (((x)->dword0 & 0x0F000000) >> 24) 119 #define ISO_TD_GET_DI(x) (((x)->dword0 & 0x00E00000) >> 21) 120 #define ISO_TD_GET_SF(x) ((x)->dword0 & 0x0000FFFF) 121 #define ISO_TD_GET_BP0(x) (((x)->dword1 & 0xFFFFF000) >> 12) 122 #define ISO_TD_GET_NEXTTD(x) ((x)->dword2 & 0xFFFFFFF0) 123 #define ISO_TD_GET_BE(x) ((x)->dword3) 124 #define ISO_TD_GET_PSW0(x) ((x)->dword4 & 0x0000FFFF) 125 #define ISO_TD_GET_PSW1(x) (((x)->dword4 & 0xFFFF0000) >> 16) 126 #define ISO_TD_GET_PSW2(x) ((x)->dword5 & 0x0000FFFF) 127 #define ISO_TD_GET_PSW3(x) (((x)->dword5 & 0xFFFF0000) >> 16) 128 #define ISO_TD_GET_PSW4(x) ((x)->dword6 & 0x0000FFFF) 129 #define ISO_TD_GET_PSW5(x) (((x)->dword6 & 0xFFFF0000) >> 16) 130 #define ISO_TD_GET_PSW6(x) ((x)->dword7 & 0x0000FFFF) 131 #define ISO_TD_GET_PSW7(x) (((x)->dword7 & 0xFFFF0000) >> 16) 132 133 struct OHCI_ISO_TD { 134 Bit32u dword0; 135 Bit32u dword1; 136 Bit32u dword2; 137 Bit32u dword3; 138 Bit32u dword4; 139 Bit32u dword5; 140 Bit32u dword6; 141 Bit32u dword7; 142 }; 143 144 145 typedef struct { 146 int frame_timer_index; 147 148 struct OHCI_OP_REGS { 149 Bit16u HcRevision; 150 struct { 151 Bit32u reserved; // 21 bit reserved = 0x000000 R R 152 bool rwe; // 1 bit RemoteWakeupEnable = 0b RW R 153 bool rwc; // 1 bit RemoteWakeupConnected = 0b RW RW 154 bool ir; // 1 bit InterruptRouting = 0b RW R 155 Bit8u hcfs; // 2 bit HostControllerFuncState = 00b RW RW 156 bool ble; // 1 bit BulkListEnable = 0b RW R 157 bool cle; // 1 bit ControlListEnable = 0b RW R 158 bool ie; // 1 bit IsochronousEnable = 0b RW R 159 bool ple; // 1 bit PeriodicListEnable = 0b RW R 160 Bit8u cbsr; // 2 bit ControlBulkService Ratio = 00b RW R 161 } HcControl; // = 0x00000000 162 struct { 163 Bit16u reserved0; // 14 bit reserved = 0x000000 R R 164 Bit8u soc; // 2 bit SchedulingOverrunCount = 00b R RW 165 Bit16u reserved1; // 12 bit reserved = 0x000000 R R 166 bool ocr; // 1 bit OwnershipChangeRequest = 0b RW RW 167 bool blf; // 1 bit BulkListFilled = 0b RW RW 168 bool clf; // 1 bit ControlListFilled = 0b RW RW 169 bool hcr; // 1 bit HostControllerReset = 0b RW RW 170 } HcCommandStatus; // = 0x00000000 171 Bit32u HcInterruptStatus; 172 Bit32u HcInterruptEnable; 173 Bit32u HcHCCA; 174 Bit32u HcPeriodCurrentED; 175 Bit32u HcControlHeadED; 176 Bit32u HcControlCurrentED; 177 Bit32u HcBulkHeadED; 178 Bit32u HcBulkCurrentED; 179 Bit32u HcDoneHead; 180 struct { 181 bool fit; // 1 bit FrameIntervalToggle = 0b RW R 182 Bit16u fsmps; // 15 bit FSLargestDataPacket = TBD (0) RW R 183 Bit8u reserved; // 2 bit reserved = 00b R R 184 Bit16u fi; // 14 bit FrameInterval = 0x2EDF RW R 185 } HcFmInterval; // = 0x00002EDF 186 bool HcFmRemainingToggle; // 1 bit FrameRemainingToggle = 0b R RW 187 Bit32u HcFmNumber; 188 Bit32u HcPeriodicStart; 189 Bit16u HcLSThreshold; 190 struct { 191 Bit8u potpgt; // 8 bit PowerOnToPowerGoodTime = 0x10 RW R 192 Bit16u reserved; // 11 bit reserved = 0x000 R R 193 bool nocp; // 1 bit NoOverCurrentProtection = 0b RW R 194 bool ocpm; // 1 bit OverCurrentProtectionMode = 1b RW R 195 bool dt; // 1 bit DeviceType = 0b R R 196 bool nps; // 1 bit NoPowerSwitching = 0b RW R 197 bool psm; // 1 bit PowerSwitchingMode = 1b RW R 198 Bit8u ndp; // 8 bit NumberDownstreamPorts = NUMPORTS RW R 199 } HcRhDescriptorA; // = 0x100009xx 200 struct { 201 Bit16u ppcm; // 16 bit PortPowerControlMask = 0x0002 RW R 202 Bit16u dr; // 16 bit DeviceRemovable = 0x0000 RW R 203 } HcRhDescriptorB; // = 0x00020000 204 struct { 205 bool crwe; // 1 bit ClearRemoteWakeupEnable = 0b WC R 206 Bit16u reserved0; // 13 bit reserved = 0x000000 R R 207 bool ocic; // 1 bit OverCurrentIndicatorChange = 0b RW RW 208 bool lpsc; // 1 bit LocalPowerStatusChange(r) = 0b RW R 209 bool drwe; // 1 bit DeviceRemoteWakeupEnable(r) = 0b RW R 210 Bit16u reserved1; // 13 bit reserved = 0x000000 R R 211 bool oci; // 1 bit OverCurrentIndicator = 0b R RW 212 bool lps; // 1 bit LocalPowerStatus(r) = 0b RW R 213 } HcRhStatus; // = 0x00000000 214 } op_regs; 215 216 struct { 217 // our data 218 usb_device_c *device; // device connected to this port 219 220 struct { 221 Bit16u reserved0; // 11 bit reserved = 0x000000 R R 222 bool prsc; // 1 bit PortResetStatusChange = 0b RW RW 223 bool ocic; // 1 bit OverCurrentIndicatorChange = 0b RW RW 224 bool pssc; // 1 bit PortSuspendStatusChange = 0b RW RW 225 bool pesc; // 1 bit PortEnableStatusChange = 0b RW RW 226 bool csc; // 1 bit ConnectStatusChange = 0b RW RW 227 Bit8u reserved1; // 6 bit reserved = 0x00 R R 228 bool lsda; // 1 bit LowSpeedDeviceAttached = 0b RW RW 229 bool pps; // 1 bit PortPowerStatus = 0b RW RW 230 Bit8u reserved2; // 3 bit reserved = 0x0 R R 231 bool prs; // 1 bit PortResetStatus = 0b RW RW 232 bool poci; // 1 bit PortOverCurrentIndicator = 0b RW RW 233 bool pss; // 1 bit PortSuspendStatus = 0b RW RW 234 bool pes; // 1 bit PortEnableStatus = 0b RW RW 235 bool ccs; // 1 bit CurrentConnectStatus = 0b RW RW 236 } HcRhPortStatus; 237 } usb_port[USB_OHCI_PORTS]; 238 239 Bit8u devfunc; 240 unsigned ohci_done_count; 241 bool use_control_head; 242 bool use_bulk_head; 243 Bit64u sof_time; 244 245 Bit8u device_change; 246 int rt_conf_id; 247 } bx_usb_ohci_t; 248 249 250 251 class bx_usb_ohci_c : public bx_pci_device_c { 252 public: 253 bx_usb_ohci_c(); 254 virtual ~bx_usb_ohci_c(); 255 virtual void init(void); 256 virtual void reset(unsigned); 257 virtual void register_state(void); 258 virtual void after_restore_state(void); 259 260 virtual void pci_write_handler(Bit8u address, Bit32u value, unsigned io_len); 261 262 void event_handler(int event, USBPacket *packet, int port); 263 264 private: 265 266 bx_usb_ohci_t hub; 267 268 USBAsync *packets; 269 270 static void reset_hc(); 271 static void reset_port(int); 272 static void update_irq(); 273 static void set_interrupt(Bit32u value); 274 275 static void init_device(Bit8u port, bx_list_c *portconf); 276 static void remove_device(Bit8u port); 277 static int broadcast_packet(USBPacket *p); 278 static bool usb_set_connect_status(Bit8u port, bool connected); 279 280 static void usb_frame_handler(void *); 281 void usb_frame_timer(void); 282 283 static Bit32u get_frame_remaining(void); 284 285 void process_lists(); 286 bool process_ed(struct OHCI_ED *, const Bit32u); 287 bool process_td(struct OHCI_TD *, struct OHCI_ED *); 288 289 #if BX_USE_USB_OHCI_SMF 290 static bool read_handler(bx_phy_address addr, unsigned len, void *data, void *param); 291 static bool write_handler(bx_phy_address addr, unsigned len, void *data, void *param); 292 #else 293 bool read_handler(bx_phy_address addr, unsigned len, void *data, void *param); 294 bool write_handler(bx_phy_address addr, unsigned len, void *data, void *param); 295 #endif 296 297 static void runtime_config_handler(void *); 298 void runtime_config(void); 299 300 static Bit64s usb_param_handler(bx_param_c *param, bool set, Bit64s val); 301 static bool usb_param_enable_handler(bx_param_c *param, bool en); 302 }; 303 304 #endif // BX_IODEV_USB_OHCI_H 305