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