xref: /openbmc/qemu/hw/usb/hcd-ohci.c (revision 0b8fa32f)
1f1ae32a1SGerd Hoffmann /*
2f1ae32a1SGerd Hoffmann  * QEMU USB OHCI Emulation
3f1ae32a1SGerd Hoffmann  * Copyright (c) 2004 Gianni Tedesco
4f1ae32a1SGerd Hoffmann  * Copyright (c) 2006 CodeSourcery
5f1ae32a1SGerd Hoffmann  * Copyright (c) 2006 Openedhand Ltd.
6f1ae32a1SGerd Hoffmann  *
7f1ae32a1SGerd Hoffmann  * This library is free software; you can redistribute it and/or
8f1ae32a1SGerd Hoffmann  * modify it under the terms of the GNU Lesser General Public
9f1ae32a1SGerd Hoffmann  * License as published by the Free Software Foundation; either
10f1ae32a1SGerd Hoffmann  * version 2 of the License, or (at your option) any later version.
11f1ae32a1SGerd Hoffmann  *
12f1ae32a1SGerd Hoffmann  * This library is distributed in the hope that it will be useful,
13f1ae32a1SGerd Hoffmann  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14f1ae32a1SGerd Hoffmann  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15f1ae32a1SGerd Hoffmann  * Lesser General Public License for more details.
16f1ae32a1SGerd Hoffmann  *
17f1ae32a1SGerd Hoffmann  * You should have received a copy of the GNU Lesser General Public
18f1ae32a1SGerd Hoffmann  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19f1ae32a1SGerd Hoffmann  *
20f1ae32a1SGerd Hoffmann  * TODO:
21f1ae32a1SGerd Hoffmann  *  o Isochronous transfers
22f1ae32a1SGerd Hoffmann  *  o Allocate bandwidth in frames properly
23f1ae32a1SGerd Hoffmann  *  o Disable timers when nothing needs to be done, or remove timer usage
24f1ae32a1SGerd Hoffmann  *    all together.
25f1ae32a1SGerd Hoffmann  *  o BIOS work to boot from USB storage
26f1ae32a1SGerd Hoffmann */
27f1ae32a1SGerd Hoffmann 
28e532b2e0SPeter Maydell #include "qemu/osdep.h"
29f1ae32a1SGerd Hoffmann #include "hw/hw.h"
30da34e65cSMarkus Armbruster #include "qapi/error.h"
31*0b8fa32fSMarkus Armbruster #include "qemu/module.h"
321de7afc9SPaolo Bonzini #include "qemu/timer.h"
33f1ae32a1SGerd Hoffmann #include "hw/usb.h"
34f1ae32a1SGerd Hoffmann #include "hw/sysbus.h"
359ac6a217SDavid Gibson #include "hw/qdev-dma.h"
36dc1f5988SAlexey Kardashevskiy #include "trace.h"
3734d97308SThomas Huth #include "hcd-ohci.h"
38f1ae32a1SGerd Hoffmann 
39f1ae32a1SGerd Hoffmann /* This causes frames to occur 1000x slower */
40f1ae32a1SGerd Hoffmann //#define OHCI_TIME_WARP 1
41f1ae32a1SGerd Hoffmann 
42ab6b1105SGerd Hoffmann #define ED_LINK_LIMIT 32
4395ed5693SLi Qiang 
44f1ae32a1SGerd Hoffmann static int64_t usb_frame_time;
45f1ae32a1SGerd Hoffmann static int64_t usb_bit_time;
46f1ae32a1SGerd Hoffmann 
47f1ae32a1SGerd Hoffmann /* Host Controller Communications Area */
48f1ae32a1SGerd Hoffmann struct ohci_hcca {
49f1ae32a1SGerd Hoffmann     uint32_t intr[32];
50f1ae32a1SGerd Hoffmann     uint16_t frame, pad;
51f1ae32a1SGerd Hoffmann     uint32_t done;
52f1ae32a1SGerd Hoffmann };
5386e18caeSWei Yang #define HCCA_WRITEBACK_OFFSET   offsetof(struct ohci_hcca, frame)
5486e18caeSWei Yang #define HCCA_WRITEBACK_SIZE     8 /* frame, pad, done */
5586e18caeSWei Yang 
5686e18caeSWei Yang #define ED_WBACK_OFFSET offsetof(struct ohci_ed, head)
5786e18caeSWei Yang #define ED_WBACK_SIZE   4
58f1ae32a1SGerd Hoffmann 
59f1ae32a1SGerd Hoffmann static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
60f1ae32a1SGerd Hoffmann 
61f1ae32a1SGerd Hoffmann /* Bitfields for the first word of an Endpoint Desciptor.  */
62f1ae32a1SGerd Hoffmann #define OHCI_ED_FA_SHIFT  0
63f1ae32a1SGerd Hoffmann #define OHCI_ED_FA_MASK   (0x7f<<OHCI_ED_FA_SHIFT)
64f1ae32a1SGerd Hoffmann #define OHCI_ED_EN_SHIFT  7
65f1ae32a1SGerd Hoffmann #define OHCI_ED_EN_MASK   (0xf<<OHCI_ED_EN_SHIFT)
66f1ae32a1SGerd Hoffmann #define OHCI_ED_D_SHIFT   11
67f1ae32a1SGerd Hoffmann #define OHCI_ED_D_MASK    (3<<OHCI_ED_D_SHIFT)
68f1ae32a1SGerd Hoffmann #define OHCI_ED_S         (1<<13)
69f1ae32a1SGerd Hoffmann #define OHCI_ED_K         (1<<14)
70f1ae32a1SGerd Hoffmann #define OHCI_ED_F         (1<<15)
71f1ae32a1SGerd Hoffmann #define OHCI_ED_MPS_SHIFT 16
72f1ae32a1SGerd Hoffmann #define OHCI_ED_MPS_MASK  (0x7ff<<OHCI_ED_MPS_SHIFT)
73f1ae32a1SGerd Hoffmann 
74f1ae32a1SGerd Hoffmann /* Flags in the head field of an Endpoint Desciptor.  */
75f1ae32a1SGerd Hoffmann #define OHCI_ED_H         1
76f1ae32a1SGerd Hoffmann #define OHCI_ED_C         2
77f1ae32a1SGerd Hoffmann 
78f1ae32a1SGerd Hoffmann /* Bitfields for the first word of a Transfer Desciptor.  */
79f1ae32a1SGerd Hoffmann #define OHCI_TD_R         (1<<18)
80f1ae32a1SGerd Hoffmann #define OHCI_TD_DP_SHIFT  19
81f1ae32a1SGerd Hoffmann #define OHCI_TD_DP_MASK   (3<<OHCI_TD_DP_SHIFT)
82f1ae32a1SGerd Hoffmann #define OHCI_TD_DI_SHIFT  21
83f1ae32a1SGerd Hoffmann #define OHCI_TD_DI_MASK   (7<<OHCI_TD_DI_SHIFT)
84f1ae32a1SGerd Hoffmann #define OHCI_TD_T0        (1<<24)
85f1ae32a1SGerd Hoffmann #define OHCI_TD_T1        (1<<25)
86f1ae32a1SGerd Hoffmann #define OHCI_TD_EC_SHIFT  26
87f1ae32a1SGerd Hoffmann #define OHCI_TD_EC_MASK   (3<<OHCI_TD_EC_SHIFT)
88f1ae32a1SGerd Hoffmann #define OHCI_TD_CC_SHIFT  28
89f1ae32a1SGerd Hoffmann #define OHCI_TD_CC_MASK   (0xf<<OHCI_TD_CC_SHIFT)
90f1ae32a1SGerd Hoffmann 
91f1ae32a1SGerd Hoffmann /* Bitfields for the first word of an Isochronous Transfer Desciptor.  */
92f1ae32a1SGerd Hoffmann /* CC & DI - same as in the General Transfer Desciptor */
93f1ae32a1SGerd Hoffmann #define OHCI_TD_SF_SHIFT  0
94f1ae32a1SGerd Hoffmann #define OHCI_TD_SF_MASK   (0xffff<<OHCI_TD_SF_SHIFT)
95f1ae32a1SGerd Hoffmann #define OHCI_TD_FC_SHIFT  24
96f1ae32a1SGerd Hoffmann #define OHCI_TD_FC_MASK   (7<<OHCI_TD_FC_SHIFT)
97f1ae32a1SGerd Hoffmann 
98f1ae32a1SGerd Hoffmann /* Isochronous Transfer Desciptor - Offset / PacketStatusWord */
99f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_CC_SHIFT 12
100f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_CC_MASK  (0xf<<OHCI_TD_PSW_CC_SHIFT)
101f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_SIZE_SHIFT 0
102f1ae32a1SGerd Hoffmann #define OHCI_TD_PSW_SIZE_MASK  (0xfff<<OHCI_TD_PSW_SIZE_SHIFT)
103f1ae32a1SGerd Hoffmann 
104f1ae32a1SGerd Hoffmann #define OHCI_PAGE_MASK    0xfffff000
105f1ae32a1SGerd Hoffmann #define OHCI_OFFSET_MASK  0xfff
106f1ae32a1SGerd Hoffmann 
107f1ae32a1SGerd Hoffmann #define OHCI_DPTR_MASK    0xfffffff0
108f1ae32a1SGerd Hoffmann 
109f1ae32a1SGerd Hoffmann #define OHCI_BM(val, field) \
110f1ae32a1SGerd Hoffmann   (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT)
111f1ae32a1SGerd Hoffmann 
112f1ae32a1SGerd Hoffmann #define OHCI_SET_BM(val, field, newval) do { \
113f1ae32a1SGerd Hoffmann     val &= ~OHCI_##field##_MASK; \
114f1ae32a1SGerd Hoffmann     val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \
115f1ae32a1SGerd Hoffmann     } while(0)
116f1ae32a1SGerd Hoffmann 
117f1ae32a1SGerd Hoffmann /* endpoint descriptor */
118f1ae32a1SGerd Hoffmann struct ohci_ed {
119f1ae32a1SGerd Hoffmann     uint32_t flags;
120f1ae32a1SGerd Hoffmann     uint32_t tail;
121f1ae32a1SGerd Hoffmann     uint32_t head;
122f1ae32a1SGerd Hoffmann     uint32_t next;
123f1ae32a1SGerd Hoffmann };
124f1ae32a1SGerd Hoffmann 
125f1ae32a1SGerd Hoffmann /* General transfer descriptor */
126f1ae32a1SGerd Hoffmann struct ohci_td {
127f1ae32a1SGerd Hoffmann     uint32_t flags;
128f1ae32a1SGerd Hoffmann     uint32_t cbp;
129f1ae32a1SGerd Hoffmann     uint32_t next;
130f1ae32a1SGerd Hoffmann     uint32_t be;
131f1ae32a1SGerd Hoffmann };
132f1ae32a1SGerd Hoffmann 
133f1ae32a1SGerd Hoffmann /* Isochronous transfer descriptor */
134f1ae32a1SGerd Hoffmann struct ohci_iso_td {
135f1ae32a1SGerd Hoffmann     uint32_t flags;
136f1ae32a1SGerd Hoffmann     uint32_t bp;
137f1ae32a1SGerd Hoffmann     uint32_t next;
138f1ae32a1SGerd Hoffmann     uint32_t be;
139f1ae32a1SGerd Hoffmann     uint16_t offset[8];
140f1ae32a1SGerd Hoffmann };
141f1ae32a1SGerd Hoffmann 
142f1ae32a1SGerd Hoffmann #define USB_HZ                      12000000
143f1ae32a1SGerd Hoffmann 
144f1ae32a1SGerd Hoffmann /* OHCI Local stuff */
145f1ae32a1SGerd Hoffmann #define OHCI_CTL_CBSR         ((1<<0)|(1<<1))
146f1ae32a1SGerd Hoffmann #define OHCI_CTL_PLE          (1<<2)
147f1ae32a1SGerd Hoffmann #define OHCI_CTL_IE           (1<<3)
148f1ae32a1SGerd Hoffmann #define OHCI_CTL_CLE          (1<<4)
149f1ae32a1SGerd Hoffmann #define OHCI_CTL_BLE          (1<<5)
150f1ae32a1SGerd Hoffmann #define OHCI_CTL_HCFS         ((1<<6)|(1<<7))
151f1ae32a1SGerd Hoffmann #define  OHCI_USB_RESET       0x00
152f1ae32a1SGerd Hoffmann #define  OHCI_USB_RESUME      0x40
153f1ae32a1SGerd Hoffmann #define  OHCI_USB_OPERATIONAL 0x80
154f1ae32a1SGerd Hoffmann #define  OHCI_USB_SUSPEND     0xc0
155f1ae32a1SGerd Hoffmann #define OHCI_CTL_IR           (1<<8)
156f1ae32a1SGerd Hoffmann #define OHCI_CTL_RWC          (1<<9)
157f1ae32a1SGerd Hoffmann #define OHCI_CTL_RWE          (1<<10)
158f1ae32a1SGerd Hoffmann 
159f1ae32a1SGerd Hoffmann #define OHCI_STATUS_HCR       (1<<0)
160f1ae32a1SGerd Hoffmann #define OHCI_STATUS_CLF       (1<<1)
161f1ae32a1SGerd Hoffmann #define OHCI_STATUS_BLF       (1<<2)
162f1ae32a1SGerd Hoffmann #define OHCI_STATUS_OCR       (1<<3)
163f1ae32a1SGerd Hoffmann #define OHCI_STATUS_SOC       ((1<<6)|(1<<7))
164f1ae32a1SGerd Hoffmann 
16500b01793SPeter Maydell #define OHCI_INTR_SO          (1U<<0) /* Scheduling overrun */
16600b01793SPeter Maydell #define OHCI_INTR_WD          (1U<<1) /* HcDoneHead writeback */
16700b01793SPeter Maydell #define OHCI_INTR_SF          (1U<<2) /* Start of frame */
16800b01793SPeter Maydell #define OHCI_INTR_RD          (1U<<3) /* Resume detect */
16900b01793SPeter Maydell #define OHCI_INTR_UE          (1U<<4) /* Unrecoverable error */
17000b01793SPeter Maydell #define OHCI_INTR_FNO         (1U<<5) /* Frame number overflow */
17100b01793SPeter Maydell #define OHCI_INTR_RHSC        (1U<<6) /* Root hub status change */
17200b01793SPeter Maydell #define OHCI_INTR_OC          (1U<<30) /* Ownership change */
17300b01793SPeter Maydell #define OHCI_INTR_MIE         (1U<<31) /* Master Interrupt Enable */
174f1ae32a1SGerd Hoffmann 
175f1ae32a1SGerd Hoffmann #define OHCI_HCCA_SIZE        0x100
176f1ae32a1SGerd Hoffmann #define OHCI_HCCA_MASK        0xffffff00
177f1ae32a1SGerd Hoffmann 
178f1ae32a1SGerd Hoffmann #define OHCI_EDPTR_MASK       0xfffffff0
179f1ae32a1SGerd Hoffmann 
180f1ae32a1SGerd Hoffmann #define OHCI_FMI_FI           0x00003fff
181f1ae32a1SGerd Hoffmann #define OHCI_FMI_FSMPS        0xffff0000
182f1ae32a1SGerd Hoffmann #define OHCI_FMI_FIT          0x80000000
183f1ae32a1SGerd Hoffmann 
18400b01793SPeter Maydell #define OHCI_FR_RT            (1U<<31)
185f1ae32a1SGerd Hoffmann 
186f1ae32a1SGerd Hoffmann #define OHCI_LS_THRESH        0x628
187f1ae32a1SGerd Hoffmann 
188f1ae32a1SGerd Hoffmann #define OHCI_RHA_RW_MASK      0x00000000 /* Mask of supported features.  */
189f1ae32a1SGerd Hoffmann #define OHCI_RHA_PSM          (1<<8)
190f1ae32a1SGerd Hoffmann #define OHCI_RHA_NPS          (1<<9)
191f1ae32a1SGerd Hoffmann #define OHCI_RHA_DT           (1<<10)
192f1ae32a1SGerd Hoffmann #define OHCI_RHA_OCPM         (1<<11)
193f1ae32a1SGerd Hoffmann #define OHCI_RHA_NOCP         (1<<12)
194f1ae32a1SGerd Hoffmann #define OHCI_RHA_POTPGT_MASK  0xff000000
195f1ae32a1SGerd Hoffmann 
19600b01793SPeter Maydell #define OHCI_RHS_LPS          (1U<<0)
19700b01793SPeter Maydell #define OHCI_RHS_OCI          (1U<<1)
19800b01793SPeter Maydell #define OHCI_RHS_DRWE         (1U<<15)
19900b01793SPeter Maydell #define OHCI_RHS_LPSC         (1U<<16)
20000b01793SPeter Maydell #define OHCI_RHS_OCIC         (1U<<17)
20100b01793SPeter Maydell #define OHCI_RHS_CRWE         (1U<<31)
202f1ae32a1SGerd Hoffmann 
203f1ae32a1SGerd Hoffmann #define OHCI_PORT_CCS         (1<<0)
204f1ae32a1SGerd Hoffmann #define OHCI_PORT_PES         (1<<1)
205f1ae32a1SGerd Hoffmann #define OHCI_PORT_PSS         (1<<2)
206f1ae32a1SGerd Hoffmann #define OHCI_PORT_POCI        (1<<3)
207f1ae32a1SGerd Hoffmann #define OHCI_PORT_PRS         (1<<4)
208f1ae32a1SGerd Hoffmann #define OHCI_PORT_PPS         (1<<8)
209f1ae32a1SGerd Hoffmann #define OHCI_PORT_LSDA        (1<<9)
210f1ae32a1SGerd Hoffmann #define OHCI_PORT_CSC         (1<<16)
211f1ae32a1SGerd Hoffmann #define OHCI_PORT_PESC        (1<<17)
212f1ae32a1SGerd Hoffmann #define OHCI_PORT_PSSC        (1<<18)
213f1ae32a1SGerd Hoffmann #define OHCI_PORT_OCIC        (1<<19)
214f1ae32a1SGerd Hoffmann #define OHCI_PORT_PRSC        (1<<20)
215f1ae32a1SGerd Hoffmann #define OHCI_PORT_WTC         (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \
216f1ae32a1SGerd Hoffmann                                |OHCI_PORT_OCIC|OHCI_PORT_PRSC)
217f1ae32a1SGerd Hoffmann 
218f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_SETUP     0x0
219f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_OUT       0x1
220f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_IN        0x2
221f1ae32a1SGerd Hoffmann #define OHCI_TD_DIR_RESERVED  0x3
222f1ae32a1SGerd Hoffmann 
223f1ae32a1SGerd Hoffmann #define OHCI_CC_NOERROR             0x0
224f1ae32a1SGerd Hoffmann #define OHCI_CC_CRC                 0x1
225f1ae32a1SGerd Hoffmann #define OHCI_CC_BITSTUFFING         0x2
226f1ae32a1SGerd Hoffmann #define OHCI_CC_DATATOGGLEMISMATCH  0x3
227f1ae32a1SGerd Hoffmann #define OHCI_CC_STALL               0x4
228f1ae32a1SGerd Hoffmann #define OHCI_CC_DEVICENOTRESPONDING 0x5
229f1ae32a1SGerd Hoffmann #define OHCI_CC_PIDCHECKFAILURE     0x6
230f1ae32a1SGerd Hoffmann #define OHCI_CC_UNDEXPETEDPID       0x7
231f1ae32a1SGerd Hoffmann #define OHCI_CC_DATAOVERRUN         0x8
232f1ae32a1SGerd Hoffmann #define OHCI_CC_DATAUNDERRUN        0x9
233f1ae32a1SGerd Hoffmann #define OHCI_CC_BUFFEROVERRUN       0xc
234f1ae32a1SGerd Hoffmann #define OHCI_CC_BUFFERUNDERRUN      0xd
235f1ae32a1SGerd Hoffmann 
236f1ae32a1SGerd Hoffmann #define OHCI_HRESET_FSBIR       (1 << 0)
237f1ae32a1SGerd Hoffmann 
23872e0c127SThomas Huth static void ohci_die(OHCIState *ohci)
23972e0c127SThomas Huth {
24072e0c127SThomas Huth     ohci->ohci_die(ohci);
24172e0c127SThomas Huth }
242cf66ee8eSAlexey Kardashevskiy 
243f1ae32a1SGerd Hoffmann /* Update IRQ levels */
244f1ae32a1SGerd Hoffmann static inline void ohci_intr_update(OHCIState *ohci)
245f1ae32a1SGerd Hoffmann {
246f1ae32a1SGerd Hoffmann     int level = 0;
247f1ae32a1SGerd Hoffmann 
248f1ae32a1SGerd Hoffmann     if ((ohci->intr & OHCI_INTR_MIE) &&
249f1ae32a1SGerd Hoffmann         (ohci->intr_status & ohci->intr))
250f1ae32a1SGerd Hoffmann         level = 1;
251f1ae32a1SGerd Hoffmann 
252f1ae32a1SGerd Hoffmann     qemu_set_irq(ohci->irq, level);
253f1ae32a1SGerd Hoffmann }
254f1ae32a1SGerd Hoffmann 
255f1ae32a1SGerd Hoffmann /* Set an interrupt */
256f1ae32a1SGerd Hoffmann static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
257f1ae32a1SGerd Hoffmann {
258f1ae32a1SGerd Hoffmann     ohci->intr_status |= intr;
259f1ae32a1SGerd Hoffmann     ohci_intr_update(ohci);
260f1ae32a1SGerd Hoffmann }
261f1ae32a1SGerd Hoffmann 
262f1ae32a1SGerd Hoffmann /* Attach or detach a device on a root hub port.  */
263f1ae32a1SGerd Hoffmann static void ohci_attach(USBPort *port1)
264f1ae32a1SGerd Hoffmann {
265f1ae32a1SGerd Hoffmann     OHCIState *s = port1->opaque;
266f1ae32a1SGerd Hoffmann     OHCIPort *port = &s->rhport[port1->index];
267f1ae32a1SGerd Hoffmann     uint32_t old_state = port->ctrl;
268f1ae32a1SGerd Hoffmann 
269f1ae32a1SGerd Hoffmann     /* set connect status */
270f1ae32a1SGerd Hoffmann     port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
271f1ae32a1SGerd Hoffmann 
272f1ae32a1SGerd Hoffmann     /* update speed */
273f1ae32a1SGerd Hoffmann     if (port->port.dev->speed == USB_SPEED_LOW) {
274f1ae32a1SGerd Hoffmann         port->ctrl |= OHCI_PORT_LSDA;
275f1ae32a1SGerd Hoffmann     } else {
276f1ae32a1SGerd Hoffmann         port->ctrl &= ~OHCI_PORT_LSDA;
277f1ae32a1SGerd Hoffmann     }
278f1ae32a1SGerd Hoffmann 
279f1ae32a1SGerd Hoffmann     /* notify of remote-wakeup */
280f1ae32a1SGerd Hoffmann     if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
281f1ae32a1SGerd Hoffmann         ohci_set_interrupt(s, OHCI_INTR_RD);
282f1ae32a1SGerd Hoffmann     }
283f1ae32a1SGerd Hoffmann 
284dc1f5988SAlexey Kardashevskiy     trace_usb_ohci_port_attach(port1->index);
285f1ae32a1SGerd Hoffmann 
286f1ae32a1SGerd Hoffmann     if (old_state != port->ctrl) {
287f1ae32a1SGerd Hoffmann         ohci_set_interrupt(s, OHCI_INTR_RHSC);
288f1ae32a1SGerd Hoffmann     }
289f1ae32a1SGerd Hoffmann }
290f1ae32a1SGerd Hoffmann 
291f1ae32a1SGerd Hoffmann static void ohci_detach(USBPort *port1)
292f1ae32a1SGerd Hoffmann {
293f1ae32a1SGerd Hoffmann     OHCIState *s = port1->opaque;
294f1ae32a1SGerd Hoffmann     OHCIPort *port = &s->rhport[port1->index];
295f1ae32a1SGerd Hoffmann     uint32_t old_state = port->ctrl;
296f1ae32a1SGerd Hoffmann 
297f1ae32a1SGerd Hoffmann     ohci_async_cancel_device(s, port1->dev);
298f1ae32a1SGerd Hoffmann 
299f1ae32a1SGerd Hoffmann     /* set connect status */
300f1ae32a1SGerd Hoffmann     if (port->ctrl & OHCI_PORT_CCS) {
301f1ae32a1SGerd Hoffmann         port->ctrl &= ~OHCI_PORT_CCS;
302f1ae32a1SGerd Hoffmann         port->ctrl |= OHCI_PORT_CSC;
303f1ae32a1SGerd Hoffmann     }
304f1ae32a1SGerd Hoffmann     /* disable port */
305f1ae32a1SGerd Hoffmann     if (port->ctrl & OHCI_PORT_PES) {
306f1ae32a1SGerd Hoffmann         port->ctrl &= ~OHCI_PORT_PES;
307f1ae32a1SGerd Hoffmann         port->ctrl |= OHCI_PORT_PESC;
308f1ae32a1SGerd Hoffmann     }
309dc1f5988SAlexey Kardashevskiy     trace_usb_ohci_port_detach(port1->index);
310f1ae32a1SGerd Hoffmann 
311f1ae32a1SGerd Hoffmann     if (old_state != port->ctrl) {
312f1ae32a1SGerd Hoffmann         ohci_set_interrupt(s, OHCI_INTR_RHSC);
313f1ae32a1SGerd Hoffmann     }
314f1ae32a1SGerd Hoffmann }
315f1ae32a1SGerd Hoffmann 
316f1ae32a1SGerd Hoffmann static void ohci_wakeup(USBPort *port1)
317f1ae32a1SGerd Hoffmann {
318f1ae32a1SGerd Hoffmann     OHCIState *s = port1->opaque;
319f1ae32a1SGerd Hoffmann     OHCIPort *port = &s->rhport[port1->index];
320f1ae32a1SGerd Hoffmann     uint32_t intr = 0;
321f1ae32a1SGerd Hoffmann     if (port->ctrl & OHCI_PORT_PSS) {
322dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_port_wakeup(port1->index);
323f1ae32a1SGerd Hoffmann         port->ctrl |= OHCI_PORT_PSSC;
324f1ae32a1SGerd Hoffmann         port->ctrl &= ~OHCI_PORT_PSS;
325f1ae32a1SGerd Hoffmann         intr = OHCI_INTR_RHSC;
326f1ae32a1SGerd Hoffmann     }
327f1ae32a1SGerd Hoffmann     /* Note that the controller can be suspended even if this port is not */
328f1ae32a1SGerd Hoffmann     if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
329dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_remote_wakeup(s->name);
330f1ae32a1SGerd Hoffmann         /* This is the one state transition the controller can do by itself */
331f1ae32a1SGerd Hoffmann         s->ctl &= ~OHCI_CTL_HCFS;
332f1ae32a1SGerd Hoffmann         s->ctl |= OHCI_USB_RESUME;
333f1ae32a1SGerd Hoffmann         /* In suspend mode only ResumeDetected is possible, not RHSC:
334f1ae32a1SGerd Hoffmann          * see the OHCI spec 5.1.2.3.
335f1ae32a1SGerd Hoffmann          */
336f1ae32a1SGerd Hoffmann         intr = OHCI_INTR_RD;
337f1ae32a1SGerd Hoffmann     }
338f1ae32a1SGerd Hoffmann     ohci_set_interrupt(s, intr);
339f1ae32a1SGerd Hoffmann }
340f1ae32a1SGerd Hoffmann 
341f1ae32a1SGerd Hoffmann static void ohci_child_detach(USBPort *port1, USBDevice *child)
342f1ae32a1SGerd Hoffmann {
343f1ae32a1SGerd Hoffmann     OHCIState *s = port1->opaque;
344f1ae32a1SGerd Hoffmann 
345f1ae32a1SGerd Hoffmann     ohci_async_cancel_device(s, child);
346f1ae32a1SGerd Hoffmann }
347f1ae32a1SGerd Hoffmann 
348f1ae32a1SGerd Hoffmann static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
349f1ae32a1SGerd Hoffmann {
350f1ae32a1SGerd Hoffmann     USBDevice *dev;
351f1ae32a1SGerd Hoffmann     int i;
352f1ae32a1SGerd Hoffmann 
353f1ae32a1SGerd Hoffmann     for (i = 0; i < ohci->num_ports; i++) {
354f1ae32a1SGerd Hoffmann         if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) {
355f1ae32a1SGerd Hoffmann             continue;
356f1ae32a1SGerd Hoffmann         }
357f1ae32a1SGerd Hoffmann         dev = usb_find_device(&ohci->rhport[i].port, addr);
358f1ae32a1SGerd Hoffmann         if (dev != NULL) {
359f1ae32a1SGerd Hoffmann             return dev;
360f1ae32a1SGerd Hoffmann         }
361f1ae32a1SGerd Hoffmann     }
362f1ae32a1SGerd Hoffmann     return NULL;
363f1ae32a1SGerd Hoffmann }
364f1ae32a1SGerd Hoffmann 
36534d97308SThomas Huth void ohci_stop_endpoints(OHCIState *ohci)
366f79738b0SHans de Goede {
367f79738b0SHans de Goede     USBDevice *dev;
368f79738b0SHans de Goede     int i, j;
369f79738b0SHans de Goede 
370f79738b0SHans de Goede     for (i = 0; i < ohci->num_ports; i++) {
371f79738b0SHans de Goede         dev = ohci->rhport[i].port.dev;
372f79738b0SHans de Goede         if (dev && dev->attached) {
373f79738b0SHans de Goede             usb_device_ep_stopped(dev, &dev->ep_ctl);
374f79738b0SHans de Goede             for (j = 0; j < USB_MAX_ENDPOINTS; j++) {
375f79738b0SHans de Goede                 usb_device_ep_stopped(dev, &dev->ep_in[j]);
376f79738b0SHans de Goede                 usb_device_ep_stopped(dev, &dev->ep_out[j]);
377f79738b0SHans de Goede             }
378f79738b0SHans de Goede         }
379f79738b0SHans de Goede     }
380f79738b0SHans de Goede }
381f79738b0SHans de Goede 
38284d04e21SHervé Poussineau static void ohci_roothub_reset(OHCIState *ohci)
383f1ae32a1SGerd Hoffmann {
384f1ae32a1SGerd Hoffmann     OHCIPort *port;
385f1ae32a1SGerd Hoffmann     int i;
386f1ae32a1SGerd Hoffmann 
387f1ae32a1SGerd Hoffmann     ohci_bus_stop(ohci);
38884d04e21SHervé Poussineau     ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports;
38984d04e21SHervé Poussineau     ohci->rhdesc_b = 0x0; /* Impl. specific */
39084d04e21SHervé Poussineau     ohci->rhstatus = 0;
39184d04e21SHervé Poussineau 
39284d04e21SHervé Poussineau     for (i = 0; i < ohci->num_ports; i++) {
39384d04e21SHervé Poussineau         port = &ohci->rhport[i];
39484d04e21SHervé Poussineau         port->ctrl = 0;
39584d04e21SHervé Poussineau         if (port->port.dev && port->port.dev->attached) {
39684d04e21SHervé Poussineau             usb_port_reset(&port->port);
39784d04e21SHervé Poussineau         }
39884d04e21SHervé Poussineau     }
39984d04e21SHervé Poussineau     if (ohci->async_td) {
40084d04e21SHervé Poussineau         usb_cancel_packet(&ohci->usb_packet);
40184d04e21SHervé Poussineau         ohci->async_td = 0;
40284d04e21SHervé Poussineau     }
40384d04e21SHervé Poussineau     ohci_stop_endpoints(ohci);
40484d04e21SHervé Poussineau }
40584d04e21SHervé Poussineau 
40684d04e21SHervé Poussineau /* Reset the controller */
40784d04e21SHervé Poussineau static void ohci_soft_reset(OHCIState *ohci)
40884d04e21SHervé Poussineau {
40984d04e21SHervé Poussineau     trace_usb_ohci_reset(ohci->name);
41084d04e21SHervé Poussineau 
41184d04e21SHervé Poussineau     ohci_bus_stop(ohci);
41284d04e21SHervé Poussineau     ohci->ctl = (ohci->ctl & OHCI_CTL_IR) | OHCI_USB_SUSPEND;
413f1ae32a1SGerd Hoffmann     ohci->old_ctl = 0;
414f1ae32a1SGerd Hoffmann     ohci->status = 0;
415f1ae32a1SGerd Hoffmann     ohci->intr_status = 0;
416f1ae32a1SGerd Hoffmann     ohci->intr = OHCI_INTR_MIE;
417f1ae32a1SGerd Hoffmann 
418f1ae32a1SGerd Hoffmann     ohci->hcca = 0;
419f1ae32a1SGerd Hoffmann     ohci->ctrl_head = ohci->ctrl_cur = 0;
420f1ae32a1SGerd Hoffmann     ohci->bulk_head = ohci->bulk_cur = 0;
421f1ae32a1SGerd Hoffmann     ohci->per_cur = 0;
422f1ae32a1SGerd Hoffmann     ohci->done = 0;
423f1ae32a1SGerd Hoffmann     ohci->done_count = 7;
424f1ae32a1SGerd Hoffmann 
425f1ae32a1SGerd Hoffmann     /* FSMPS is marked TBD in OCHI 1.0, what gives ffs?
426f1ae32a1SGerd Hoffmann      * I took the value linux sets ...
427f1ae32a1SGerd Hoffmann      */
428f1ae32a1SGerd Hoffmann     ohci->fsmps = 0x2778;
429f1ae32a1SGerd Hoffmann     ohci->fi = 0x2edf;
430f1ae32a1SGerd Hoffmann     ohci->fit = 0;
431f1ae32a1SGerd Hoffmann     ohci->frt = 0;
432f1ae32a1SGerd Hoffmann     ohci->frame_number = 0;
433f1ae32a1SGerd Hoffmann     ohci->pstart = 0;
434f1ae32a1SGerd Hoffmann     ohci->lst = OHCI_LS_THRESH;
43584d04e21SHervé Poussineau }
436f1ae32a1SGerd Hoffmann 
43734d97308SThomas Huth void ohci_hard_reset(OHCIState *ohci)
438f1ae32a1SGerd Hoffmann {
43984d04e21SHervé Poussineau     ohci_soft_reset(ohci);
44084d04e21SHervé Poussineau     ohci->ctl = 0;
44184d04e21SHervé Poussineau     ohci_roothub_reset(ohci);
442f1ae32a1SGerd Hoffmann }
443f1ae32a1SGerd Hoffmann 
444f1ae32a1SGerd Hoffmann /* Get an array of dwords from main memory */
445f1ae32a1SGerd Hoffmann static inline int get_dwords(OHCIState *ohci,
4469ac6a217SDavid Gibson                              dma_addr_t addr, uint32_t *buf, int num)
447f1ae32a1SGerd Hoffmann {
448f1ae32a1SGerd Hoffmann     int i;
449f1ae32a1SGerd Hoffmann 
450f1ae32a1SGerd Hoffmann     addr += ohci->localmem_base;
451f1ae32a1SGerd Hoffmann 
452f1ae32a1SGerd Hoffmann     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
453cf66ee8eSAlexey Kardashevskiy         if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) {
454cf66ee8eSAlexey Kardashevskiy             return -1;
455cf66ee8eSAlexey Kardashevskiy         }
456f1ae32a1SGerd Hoffmann         *buf = le32_to_cpu(*buf);
457f1ae32a1SGerd Hoffmann     }
458f1ae32a1SGerd Hoffmann 
459cf66ee8eSAlexey Kardashevskiy     return 0;
460f1ae32a1SGerd Hoffmann }
461f1ae32a1SGerd Hoffmann 
462f1ae32a1SGerd Hoffmann /* Put an array of dwords in to main memory */
463f1ae32a1SGerd Hoffmann static inline int put_dwords(OHCIState *ohci,
4649ac6a217SDavid Gibson                              dma_addr_t addr, uint32_t *buf, int num)
465f1ae32a1SGerd Hoffmann {
466f1ae32a1SGerd Hoffmann     int i;
467f1ae32a1SGerd Hoffmann 
468f1ae32a1SGerd Hoffmann     addr += ohci->localmem_base;
469f1ae32a1SGerd Hoffmann 
470f1ae32a1SGerd Hoffmann     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
471f1ae32a1SGerd Hoffmann         uint32_t tmp = cpu_to_le32(*buf);
472cf66ee8eSAlexey Kardashevskiy         if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) {
473cf66ee8eSAlexey Kardashevskiy             return -1;
474cf66ee8eSAlexey Kardashevskiy         }
475f1ae32a1SGerd Hoffmann     }
476f1ae32a1SGerd Hoffmann 
477cf66ee8eSAlexey Kardashevskiy     return 0;
478f1ae32a1SGerd Hoffmann }
479f1ae32a1SGerd Hoffmann 
480f1ae32a1SGerd Hoffmann /* Get an array of words from main memory */
481f1ae32a1SGerd Hoffmann static inline int get_words(OHCIState *ohci,
4829ac6a217SDavid Gibson                             dma_addr_t addr, uint16_t *buf, int num)
483f1ae32a1SGerd Hoffmann {
484f1ae32a1SGerd Hoffmann     int i;
485f1ae32a1SGerd Hoffmann 
486f1ae32a1SGerd Hoffmann     addr += ohci->localmem_base;
487f1ae32a1SGerd Hoffmann 
488f1ae32a1SGerd Hoffmann     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
489cf66ee8eSAlexey Kardashevskiy         if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) {
490cf66ee8eSAlexey Kardashevskiy             return -1;
491cf66ee8eSAlexey Kardashevskiy         }
492f1ae32a1SGerd Hoffmann         *buf = le16_to_cpu(*buf);
493f1ae32a1SGerd Hoffmann     }
494f1ae32a1SGerd Hoffmann 
495cf66ee8eSAlexey Kardashevskiy     return 0;
496f1ae32a1SGerd Hoffmann }
497f1ae32a1SGerd Hoffmann 
498f1ae32a1SGerd Hoffmann /* Put an array of words in to main memory */
499f1ae32a1SGerd Hoffmann static inline int put_words(OHCIState *ohci,
5009ac6a217SDavid Gibson                             dma_addr_t addr, uint16_t *buf, int num)
501f1ae32a1SGerd Hoffmann {
502f1ae32a1SGerd Hoffmann     int i;
503f1ae32a1SGerd Hoffmann 
504f1ae32a1SGerd Hoffmann     addr += ohci->localmem_base;
505f1ae32a1SGerd Hoffmann 
506f1ae32a1SGerd Hoffmann     for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
507f1ae32a1SGerd Hoffmann         uint16_t tmp = cpu_to_le16(*buf);
508cf66ee8eSAlexey Kardashevskiy         if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) {
509cf66ee8eSAlexey Kardashevskiy             return -1;
510cf66ee8eSAlexey Kardashevskiy         }
511f1ae32a1SGerd Hoffmann     }
512f1ae32a1SGerd Hoffmann 
513cf66ee8eSAlexey Kardashevskiy     return 0;
514f1ae32a1SGerd Hoffmann }
515f1ae32a1SGerd Hoffmann 
516f1ae32a1SGerd Hoffmann static inline int ohci_read_ed(OHCIState *ohci,
5179ac6a217SDavid Gibson                                dma_addr_t addr, struct ohci_ed *ed)
518f1ae32a1SGerd Hoffmann {
519f1ae32a1SGerd Hoffmann     return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
520f1ae32a1SGerd Hoffmann }
521f1ae32a1SGerd Hoffmann 
522f1ae32a1SGerd Hoffmann static inline int ohci_read_td(OHCIState *ohci,
5239ac6a217SDavid Gibson                                dma_addr_t addr, struct ohci_td *td)
524f1ae32a1SGerd Hoffmann {
525f1ae32a1SGerd Hoffmann     return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
526f1ae32a1SGerd Hoffmann }
527f1ae32a1SGerd Hoffmann 
528f1ae32a1SGerd Hoffmann static inline int ohci_read_iso_td(OHCIState *ohci,
5299ac6a217SDavid Gibson                                    dma_addr_t addr, struct ohci_iso_td *td)
530f1ae32a1SGerd Hoffmann {
531cf66ee8eSAlexey Kardashevskiy     return get_dwords(ohci, addr, (uint32_t *)td, 4) ||
532cf66ee8eSAlexey Kardashevskiy            get_words(ohci, addr + 16, td->offset, 8);
533f1ae32a1SGerd Hoffmann }
534f1ae32a1SGerd Hoffmann 
535f1ae32a1SGerd Hoffmann static inline int ohci_read_hcca(OHCIState *ohci,
5369ac6a217SDavid Gibson                                  dma_addr_t addr, struct ohci_hcca *hcca)
537f1ae32a1SGerd Hoffmann {
538cf66ee8eSAlexey Kardashevskiy     return dma_memory_read(ohci->as, addr + ohci->localmem_base,
539cf66ee8eSAlexey Kardashevskiy                            hcca, sizeof(*hcca));
540f1ae32a1SGerd Hoffmann }
541f1ae32a1SGerd Hoffmann 
542f1ae32a1SGerd Hoffmann static inline int ohci_put_ed(OHCIState *ohci,
5439ac6a217SDavid Gibson                               dma_addr_t addr, struct ohci_ed *ed)
544f1ae32a1SGerd Hoffmann {
54586e18caeSWei Yang     /* ed->tail is under control of the HCD.
54686e18caeSWei Yang      * Since just ed->head is changed by HC, just write back this
54786e18caeSWei Yang      */
54886e18caeSWei Yang 
54986e18caeSWei Yang     return put_dwords(ohci, addr + ED_WBACK_OFFSET,
55086e18caeSWei Yang                       (uint32_t *)((char *)ed + ED_WBACK_OFFSET),
55186e18caeSWei Yang                       ED_WBACK_SIZE >> 2);
552f1ae32a1SGerd Hoffmann }
553f1ae32a1SGerd Hoffmann 
554f1ae32a1SGerd Hoffmann static inline int ohci_put_td(OHCIState *ohci,
5559ac6a217SDavid Gibson                               dma_addr_t addr, struct ohci_td *td)
556f1ae32a1SGerd Hoffmann {
557f1ae32a1SGerd Hoffmann     return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
558f1ae32a1SGerd Hoffmann }
559f1ae32a1SGerd Hoffmann 
560f1ae32a1SGerd Hoffmann static inline int ohci_put_iso_td(OHCIState *ohci,
5619ac6a217SDavid Gibson                                   dma_addr_t addr, struct ohci_iso_td *td)
562f1ae32a1SGerd Hoffmann {
563cae7f29cSJack Un     return put_dwords(ohci, addr, (uint32_t *)td, 4) ||
564cae7f29cSJack Un            put_words(ohci, addr + 16, td->offset, 8);
565f1ae32a1SGerd Hoffmann }
566f1ae32a1SGerd Hoffmann 
567f1ae32a1SGerd Hoffmann static inline int ohci_put_hcca(OHCIState *ohci,
5689ac6a217SDavid Gibson                                 dma_addr_t addr, struct ohci_hcca *hcca)
569f1ae32a1SGerd Hoffmann {
570cf66ee8eSAlexey Kardashevskiy     return dma_memory_write(ohci->as,
5719ac6a217SDavid Gibson                             addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET,
57286e18caeSWei Yang                             (char *)hcca + HCCA_WRITEBACK_OFFSET,
57386e18caeSWei Yang                             HCCA_WRITEBACK_SIZE);
574f1ae32a1SGerd Hoffmann }
575f1ae32a1SGerd Hoffmann 
576f1ae32a1SGerd Hoffmann /* Read/Write the contents of a TD from/to main memory.  */
577cf66ee8eSAlexey Kardashevskiy static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td,
5789ac6a217SDavid Gibson                         uint8_t *buf, int len, DMADirection dir)
579f1ae32a1SGerd Hoffmann {
5809ac6a217SDavid Gibson     dma_addr_t ptr, n;
581f1ae32a1SGerd Hoffmann 
582f1ae32a1SGerd Hoffmann     ptr = td->cbp;
583f1ae32a1SGerd Hoffmann     n = 0x1000 - (ptr & 0xfff);
584f1ae32a1SGerd Hoffmann     if (n > len)
585f1ae32a1SGerd Hoffmann         n = len;
586cf66ee8eSAlexey Kardashevskiy 
587cf66ee8eSAlexey Kardashevskiy     if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) {
588cf66ee8eSAlexey Kardashevskiy         return -1;
589cf66ee8eSAlexey Kardashevskiy     }
590cf66ee8eSAlexey Kardashevskiy     if (n == len) {
591cf66ee8eSAlexey Kardashevskiy         return 0;
592cf66ee8eSAlexey Kardashevskiy     }
593f1ae32a1SGerd Hoffmann     ptr = td->be & ~0xfffu;
594f1ae32a1SGerd Hoffmann     buf += n;
595cf66ee8eSAlexey Kardashevskiy     if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf,
596cf66ee8eSAlexey Kardashevskiy                       len - n, dir)) {
597cf66ee8eSAlexey Kardashevskiy         return -1;
598cf66ee8eSAlexey Kardashevskiy     }
599cf66ee8eSAlexey Kardashevskiy     return 0;
600f1ae32a1SGerd Hoffmann }
601f1ae32a1SGerd Hoffmann 
602f1ae32a1SGerd Hoffmann /* Read/Write the contents of an ISO TD from/to main memory.  */
603cf66ee8eSAlexey Kardashevskiy static int ohci_copy_iso_td(OHCIState *ohci,
604f1ae32a1SGerd Hoffmann                             uint32_t start_addr, uint32_t end_addr,
6059ac6a217SDavid Gibson                             uint8_t *buf, int len, DMADirection dir)
606f1ae32a1SGerd Hoffmann {
6079ac6a217SDavid Gibson     dma_addr_t ptr, n;
608f1ae32a1SGerd Hoffmann 
609f1ae32a1SGerd Hoffmann     ptr = start_addr;
610f1ae32a1SGerd Hoffmann     n = 0x1000 - (ptr & 0xfff);
611f1ae32a1SGerd Hoffmann     if (n > len)
612f1ae32a1SGerd Hoffmann         n = len;
613cf66ee8eSAlexey Kardashevskiy 
614cf66ee8eSAlexey Kardashevskiy     if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) {
615cf66ee8eSAlexey Kardashevskiy         return -1;
616cf66ee8eSAlexey Kardashevskiy     }
617cf66ee8eSAlexey Kardashevskiy     if (n == len) {
618cf66ee8eSAlexey Kardashevskiy         return 0;
619cf66ee8eSAlexey Kardashevskiy     }
620f1ae32a1SGerd Hoffmann     ptr = end_addr & ~0xfffu;
621f1ae32a1SGerd Hoffmann     buf += n;
622cf66ee8eSAlexey Kardashevskiy     if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf,
623cf66ee8eSAlexey Kardashevskiy                       len - n, dir)) {
624cf66ee8eSAlexey Kardashevskiy         return -1;
625cf66ee8eSAlexey Kardashevskiy     }
626cf66ee8eSAlexey Kardashevskiy     return 0;
627f1ae32a1SGerd Hoffmann }
628f1ae32a1SGerd Hoffmann 
629f1ae32a1SGerd Hoffmann static void ohci_process_lists(OHCIState *ohci, int completion);
630f1ae32a1SGerd Hoffmann 
631f1ae32a1SGerd Hoffmann static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
632f1ae32a1SGerd Hoffmann {
633f1ae32a1SGerd Hoffmann     OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
634dc1f5988SAlexey Kardashevskiy 
635dc1f5988SAlexey Kardashevskiy     trace_usb_ohci_async_complete();
63669e25d26SAlexey Kardashevskiy     ohci->async_complete = true;
637f1ae32a1SGerd Hoffmann     ohci_process_lists(ohci, 1);
638f1ae32a1SGerd Hoffmann }
639f1ae32a1SGerd Hoffmann 
640f1ae32a1SGerd Hoffmann #define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b)))
641f1ae32a1SGerd Hoffmann 
642f1ae32a1SGerd Hoffmann static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
643f1ae32a1SGerd Hoffmann                                int completion)
644f1ae32a1SGerd Hoffmann {
645f1ae32a1SGerd Hoffmann     int dir;
646f1ae32a1SGerd Hoffmann     size_t len = 0;
647f1ae32a1SGerd Hoffmann     const char *str = NULL;
648f1ae32a1SGerd Hoffmann     int pid;
649f1ae32a1SGerd Hoffmann     int ret;
650f1ae32a1SGerd Hoffmann     int i;
651f1ae32a1SGerd Hoffmann     USBDevice *dev;
652f1ae32a1SGerd Hoffmann     USBEndpoint *ep;
653f1ae32a1SGerd Hoffmann     struct ohci_iso_td iso_td;
654f1ae32a1SGerd Hoffmann     uint32_t addr;
655f1ae32a1SGerd Hoffmann     uint16_t starting_frame;
656f1ae32a1SGerd Hoffmann     int16_t relative_frame_number;
657f1ae32a1SGerd Hoffmann     int frame_count;
658f1ae32a1SGerd Hoffmann     uint32_t start_offset, next_offset, end_offset = 0;
659f1ae32a1SGerd Hoffmann     uint32_t start_addr, end_addr;
660f1ae32a1SGerd Hoffmann 
661f1ae32a1SGerd Hoffmann     addr = ed->head & OHCI_DPTR_MASK;
662f1ae32a1SGerd Hoffmann 
663cf66ee8eSAlexey Kardashevskiy     if (ohci_read_iso_td(ohci, addr, &iso_td)) {
664dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_iso_td_read_failed(addr);
665cf66ee8eSAlexey Kardashevskiy         ohci_die(ohci);
66626f670a2SLi Qiang         return 1;
667f1ae32a1SGerd Hoffmann     }
668f1ae32a1SGerd Hoffmann 
669f1ae32a1SGerd Hoffmann     starting_frame = OHCI_BM(iso_td.flags, TD_SF);
670f1ae32a1SGerd Hoffmann     frame_count = OHCI_BM(iso_td.flags, TD_FC);
671f1ae32a1SGerd Hoffmann     relative_frame_number = USUB(ohci->frame_number, starting_frame);
672f1ae32a1SGerd Hoffmann 
673dc1f5988SAlexey Kardashevskiy     trace_usb_ohci_iso_td_head(
674f1ae32a1SGerd Hoffmann            ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK,
675f1ae32a1SGerd Hoffmann            iso_td.flags, iso_td.bp, iso_td.next, iso_td.be,
676f1ae32a1SGerd Hoffmann            ohci->frame_number, starting_frame,
677bc0d104cSAlex Bennée            frame_count, relative_frame_number);
6783af8f177SAlexey Kardashevskiy     trace_usb_ohci_iso_td_head_offset(
6793af8f177SAlexey Kardashevskiy            iso_td.offset[0], iso_td.offset[1],
6803af8f177SAlexey Kardashevskiy            iso_td.offset[2], iso_td.offset[3],
6813af8f177SAlexey Kardashevskiy            iso_td.offset[4], iso_td.offset[5],
6823af8f177SAlexey Kardashevskiy            iso_td.offset[6], iso_td.offset[7]);
683f1ae32a1SGerd Hoffmann 
684f1ae32a1SGerd Hoffmann     if (relative_frame_number < 0) {
685dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_iso_td_relative_frame_number_neg(relative_frame_number);
686f1ae32a1SGerd Hoffmann         return 1;
687f1ae32a1SGerd Hoffmann     } else if (relative_frame_number > frame_count) {
688f1ae32a1SGerd Hoffmann         /* ISO TD expired - retire the TD to the Done Queue and continue with
689f1ae32a1SGerd Hoffmann            the next ISO TD of the same ED */
690dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_iso_td_relative_frame_number_big(relative_frame_number,
691f1ae32a1SGerd Hoffmann                                                         frame_count);
692f1ae32a1SGerd Hoffmann         OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
693f1ae32a1SGerd Hoffmann         ed->head &= ~OHCI_DPTR_MASK;
694f1ae32a1SGerd Hoffmann         ed->head |= (iso_td.next & OHCI_DPTR_MASK);
695f1ae32a1SGerd Hoffmann         iso_td.next = ohci->done;
696f1ae32a1SGerd Hoffmann         ohci->done = addr;
697f1ae32a1SGerd Hoffmann         i = OHCI_BM(iso_td.flags, TD_DI);
698f1ae32a1SGerd Hoffmann         if (i < ohci->done_count)
699f1ae32a1SGerd Hoffmann             ohci->done_count = i;
700cf66ee8eSAlexey Kardashevskiy         if (ohci_put_iso_td(ohci, addr, &iso_td)) {
701cf66ee8eSAlexey Kardashevskiy             ohci_die(ohci);
702cf66ee8eSAlexey Kardashevskiy             return 1;
703cf66ee8eSAlexey Kardashevskiy         }
704f1ae32a1SGerd Hoffmann         return 0;
705f1ae32a1SGerd Hoffmann     }
706f1ae32a1SGerd Hoffmann 
707f1ae32a1SGerd Hoffmann     dir = OHCI_BM(ed->flags, ED_D);
708f1ae32a1SGerd Hoffmann     switch (dir) {
709f1ae32a1SGerd Hoffmann     case OHCI_TD_DIR_IN:
710f1ae32a1SGerd Hoffmann         str = "in";
711f1ae32a1SGerd Hoffmann         pid = USB_TOKEN_IN;
712f1ae32a1SGerd Hoffmann         break;
713f1ae32a1SGerd Hoffmann     case OHCI_TD_DIR_OUT:
714f1ae32a1SGerd Hoffmann         str = "out";
715f1ae32a1SGerd Hoffmann         pid = USB_TOKEN_OUT;
716f1ae32a1SGerd Hoffmann         break;
717f1ae32a1SGerd Hoffmann     case OHCI_TD_DIR_SETUP:
718f1ae32a1SGerd Hoffmann         str = "setup";
719f1ae32a1SGerd Hoffmann         pid = USB_TOKEN_SETUP;
720f1ae32a1SGerd Hoffmann         break;
721f1ae32a1SGerd Hoffmann     default:
722dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_iso_td_bad_direction(dir);
723f1ae32a1SGerd Hoffmann         return 1;
724f1ae32a1SGerd Hoffmann     }
725f1ae32a1SGerd Hoffmann 
726f1ae32a1SGerd Hoffmann     if (!iso_td.bp || !iso_td.be) {
727dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_iso_td_bad_bp_be(iso_td.bp, iso_td.be);
728f1ae32a1SGerd Hoffmann         return 1;
729f1ae32a1SGerd Hoffmann     }
730f1ae32a1SGerd Hoffmann 
731f1ae32a1SGerd Hoffmann     start_offset = iso_td.offset[relative_frame_number];
732f1ae32a1SGerd Hoffmann     next_offset = iso_td.offset[relative_frame_number + 1];
733f1ae32a1SGerd Hoffmann 
734f1ae32a1SGerd Hoffmann     if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) ||
735f1ae32a1SGerd Hoffmann         ((relative_frame_number < frame_count) &&
736f1ae32a1SGerd Hoffmann          !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) {
737dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_iso_td_bad_cc_not_accessed(start_offset, next_offset);
738f1ae32a1SGerd Hoffmann         return 1;
739f1ae32a1SGerd Hoffmann     }
740f1ae32a1SGerd Hoffmann 
741f1ae32a1SGerd Hoffmann     if ((relative_frame_number < frame_count) && (start_offset > next_offset)) {
742dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_iso_td_bad_cc_overrun(start_offset, next_offset);
743f1ae32a1SGerd Hoffmann         return 1;
744f1ae32a1SGerd Hoffmann     }
745f1ae32a1SGerd Hoffmann 
746f1ae32a1SGerd Hoffmann     if ((start_offset & 0x1000) == 0) {
747f1ae32a1SGerd Hoffmann         start_addr = (iso_td.bp & OHCI_PAGE_MASK) |
748f1ae32a1SGerd Hoffmann             (start_offset & OHCI_OFFSET_MASK);
749f1ae32a1SGerd Hoffmann     } else {
750f1ae32a1SGerd Hoffmann         start_addr = (iso_td.be & OHCI_PAGE_MASK) |
751f1ae32a1SGerd Hoffmann             (start_offset & OHCI_OFFSET_MASK);
752f1ae32a1SGerd Hoffmann     }
753f1ae32a1SGerd Hoffmann 
754f1ae32a1SGerd Hoffmann     if (relative_frame_number < frame_count) {
755f1ae32a1SGerd Hoffmann         end_offset = next_offset - 1;
756f1ae32a1SGerd Hoffmann         if ((end_offset & 0x1000) == 0) {
757f1ae32a1SGerd Hoffmann             end_addr = (iso_td.bp & OHCI_PAGE_MASK) |
758f1ae32a1SGerd Hoffmann                 (end_offset & OHCI_OFFSET_MASK);
759f1ae32a1SGerd Hoffmann         } else {
760f1ae32a1SGerd Hoffmann             end_addr = (iso_td.be & OHCI_PAGE_MASK) |
761f1ae32a1SGerd Hoffmann                 (end_offset & OHCI_OFFSET_MASK);
762f1ae32a1SGerd Hoffmann         }
763f1ae32a1SGerd Hoffmann     } else {
764f1ae32a1SGerd Hoffmann         /* Last packet in the ISO TD */
765f1ae32a1SGerd Hoffmann         end_addr = iso_td.be;
766f1ae32a1SGerd Hoffmann     }
767f1ae32a1SGerd Hoffmann 
768f1ae32a1SGerd Hoffmann     if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) {
769f1ae32a1SGerd Hoffmann         len = (end_addr & OHCI_OFFSET_MASK) + 0x1001
770f1ae32a1SGerd Hoffmann             - (start_addr & OHCI_OFFSET_MASK);
771f1ae32a1SGerd Hoffmann     } else {
772f1ae32a1SGerd Hoffmann         len = end_addr - start_addr + 1;
773f1ae32a1SGerd Hoffmann     }
774f1ae32a1SGerd Hoffmann 
775f1ae32a1SGerd Hoffmann     if (len && dir != OHCI_TD_DIR_IN) {
776cf66ee8eSAlexey Kardashevskiy         if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len,
777cf66ee8eSAlexey Kardashevskiy                              DMA_DIRECTION_TO_DEVICE)) {
778cf66ee8eSAlexey Kardashevskiy             ohci_die(ohci);
779cf66ee8eSAlexey Kardashevskiy             return 1;
780cf66ee8eSAlexey Kardashevskiy         }
781f1ae32a1SGerd Hoffmann     }
782f1ae32a1SGerd Hoffmann 
7839a77a0f5SHans de Goede     if (!completion) {
784a6fb2ddbSHans de Goede         bool int_req = relative_frame_number == frame_count &&
785a6fb2ddbSHans de Goede                        OHCI_BM(iso_td.flags, TD_DI) == 0;
786f1ae32a1SGerd Hoffmann         dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
78742340fc3SLiam Merwick         if (dev == NULL) {
78842340fc3SLiam Merwick             trace_usb_ohci_td_dev_error();
78942340fc3SLiam Merwick             return 1;
79042340fc3SLiam Merwick         }
791f1ae32a1SGerd Hoffmann         ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
7928550a02dSGerd Hoffmann         usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
793f1ae32a1SGerd Hoffmann         usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
7949a77a0f5SHans de Goede         usb_handle_packet(dev, &ohci->usb_packet);
7959a77a0f5SHans de Goede         if (ohci->usb_packet.status == USB_RET_ASYNC) {
79636dfe324SHans de Goede             usb_device_flush_ep_queue(dev, ep);
797f1ae32a1SGerd Hoffmann             return 1;
798f1ae32a1SGerd Hoffmann         }
799f1ae32a1SGerd Hoffmann     }
8009a77a0f5SHans de Goede     if (ohci->usb_packet.status == USB_RET_SUCCESS) {
8019a77a0f5SHans de Goede         ret = ohci->usb_packet.actual_length;
8029a77a0f5SHans de Goede     } else {
8039a77a0f5SHans de Goede         ret = ohci->usb_packet.status;
8049a77a0f5SHans de Goede     }
805f1ae32a1SGerd Hoffmann 
806dc1f5988SAlexey Kardashevskiy     trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr,
807dc1f5988SAlexey Kardashevskiy                              str, len, ret);
808f1ae32a1SGerd Hoffmann 
809f1ae32a1SGerd Hoffmann     /* Writeback */
810f1ae32a1SGerd Hoffmann     if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
811f1ae32a1SGerd Hoffmann         /* IN transfer succeeded */
812cf66ee8eSAlexey Kardashevskiy         if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret,
813cf66ee8eSAlexey Kardashevskiy                              DMA_DIRECTION_FROM_DEVICE)) {
814cf66ee8eSAlexey Kardashevskiy             ohci_die(ohci);
815cf66ee8eSAlexey Kardashevskiy             return 1;
816cf66ee8eSAlexey Kardashevskiy         }
817f1ae32a1SGerd Hoffmann         OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
818f1ae32a1SGerd Hoffmann                     OHCI_CC_NOERROR);
819f1ae32a1SGerd Hoffmann         OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);
820f1ae32a1SGerd Hoffmann     } else if (dir == OHCI_TD_DIR_OUT && ret == len) {
821f1ae32a1SGerd Hoffmann         /* OUT transfer succeeded */
822f1ae32a1SGerd Hoffmann         OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
823f1ae32a1SGerd Hoffmann                     OHCI_CC_NOERROR);
824f1ae32a1SGerd Hoffmann         OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0);
825f1ae32a1SGerd Hoffmann     } else {
826f1ae32a1SGerd Hoffmann         if (ret > (ssize_t) len) {
827dc1f5988SAlexey Kardashevskiy             trace_usb_ohci_iso_td_data_overrun(ret, len);
828f1ae32a1SGerd Hoffmann             OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
829f1ae32a1SGerd Hoffmann                         OHCI_CC_DATAOVERRUN);
830f1ae32a1SGerd Hoffmann             OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
831f1ae32a1SGerd Hoffmann                         len);
832f1ae32a1SGerd Hoffmann         } else if (ret >= 0) {
833dc1f5988SAlexey Kardashevskiy             trace_usb_ohci_iso_td_data_underrun(ret);
834f1ae32a1SGerd Hoffmann             OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
835f1ae32a1SGerd Hoffmann                         OHCI_CC_DATAUNDERRUN);
836f1ae32a1SGerd Hoffmann         } else {
837f1ae32a1SGerd Hoffmann             switch (ret) {
838f1ae32a1SGerd Hoffmann             case USB_RET_IOERROR:
839f1ae32a1SGerd Hoffmann             case USB_RET_NODEV:
840f1ae32a1SGerd Hoffmann                 OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
841f1ae32a1SGerd Hoffmann                             OHCI_CC_DEVICENOTRESPONDING);
842f1ae32a1SGerd Hoffmann                 OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
843f1ae32a1SGerd Hoffmann                             0);
844f1ae32a1SGerd Hoffmann                 break;
845f1ae32a1SGerd Hoffmann             case USB_RET_NAK:
846f1ae32a1SGerd Hoffmann             case USB_RET_STALL:
847dc1f5988SAlexey Kardashevskiy                 trace_usb_ohci_iso_td_nak(ret);
848f1ae32a1SGerd Hoffmann                 OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
849f1ae32a1SGerd Hoffmann                             OHCI_CC_STALL);
850f1ae32a1SGerd Hoffmann                 OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
851f1ae32a1SGerd Hoffmann                             0);
852f1ae32a1SGerd Hoffmann                 break;
853f1ae32a1SGerd Hoffmann             default:
854dc1f5988SAlexey Kardashevskiy                 trace_usb_ohci_iso_td_bad_response(ret);
855f1ae32a1SGerd Hoffmann                 OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
856f1ae32a1SGerd Hoffmann                             OHCI_CC_UNDEXPETEDPID);
857f1ae32a1SGerd Hoffmann                 break;
858f1ae32a1SGerd Hoffmann             }
859f1ae32a1SGerd Hoffmann         }
860f1ae32a1SGerd Hoffmann     }
861f1ae32a1SGerd Hoffmann 
862f1ae32a1SGerd Hoffmann     if (relative_frame_number == frame_count) {
863f1ae32a1SGerd Hoffmann         /* Last data packet of ISO TD - retire the TD to the Done Queue */
864f1ae32a1SGerd Hoffmann         OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR);
865f1ae32a1SGerd Hoffmann         ed->head &= ~OHCI_DPTR_MASK;
866f1ae32a1SGerd Hoffmann         ed->head |= (iso_td.next & OHCI_DPTR_MASK);
867f1ae32a1SGerd Hoffmann         iso_td.next = ohci->done;
868f1ae32a1SGerd Hoffmann         ohci->done = addr;
869f1ae32a1SGerd Hoffmann         i = OHCI_BM(iso_td.flags, TD_DI);
870f1ae32a1SGerd Hoffmann         if (i < ohci->done_count)
871f1ae32a1SGerd Hoffmann             ohci->done_count = i;
872f1ae32a1SGerd Hoffmann     }
873cf66ee8eSAlexey Kardashevskiy     if (ohci_put_iso_td(ohci, addr, &iso_td)) {
874cf66ee8eSAlexey Kardashevskiy         ohci_die(ohci);
875cf66ee8eSAlexey Kardashevskiy     }
876f1ae32a1SGerd Hoffmann     return 1;
877f1ae32a1SGerd Hoffmann }
878f1ae32a1SGerd Hoffmann 
879dc1f5988SAlexey Kardashevskiy static void ohci_td_pkt(const char *msg, const uint8_t *buf, size_t len)
880dc1f5988SAlexey Kardashevskiy {
881d87aa138SStefan Hajnoczi     bool print16;
882d87aa138SStefan Hajnoczi     bool printall;
883dc1f5988SAlexey Kardashevskiy     const int width = 16;
884dc1f5988SAlexey Kardashevskiy     int i;
885dc1f5988SAlexey Kardashevskiy     char tmp[3 * width + 1];
886dc1f5988SAlexey Kardashevskiy     char *p = tmp;
887dc1f5988SAlexey Kardashevskiy 
888d87aa138SStefan Hajnoczi     print16 = !!trace_event_get_state_backends(TRACE_USB_OHCI_TD_PKT_SHORT);
889d87aa138SStefan Hajnoczi     printall = !!trace_event_get_state_backends(TRACE_USB_OHCI_TD_PKT_FULL);
890d87aa138SStefan Hajnoczi 
891dc1f5988SAlexey Kardashevskiy     if (!printall && !print16) {
892dc1f5988SAlexey Kardashevskiy         return;
893dc1f5988SAlexey Kardashevskiy     }
894dc1f5988SAlexey Kardashevskiy 
895dc1f5988SAlexey Kardashevskiy     for (i = 0; ; i++) {
896dc1f5988SAlexey Kardashevskiy         if (i && (!(i % width) || (i == len))) {
897dc1f5988SAlexey Kardashevskiy             if (!printall) {
898dc1f5988SAlexey Kardashevskiy                 trace_usb_ohci_td_pkt_short(msg, tmp);
899dc1f5988SAlexey Kardashevskiy                 break;
900dc1f5988SAlexey Kardashevskiy             }
901dc1f5988SAlexey Kardashevskiy             trace_usb_ohci_td_pkt_full(msg, tmp);
902dc1f5988SAlexey Kardashevskiy             p = tmp;
903dc1f5988SAlexey Kardashevskiy             *p = 0;
904dc1f5988SAlexey Kardashevskiy         }
905dc1f5988SAlexey Kardashevskiy         if (i == len) {
906dc1f5988SAlexey Kardashevskiy             break;
907dc1f5988SAlexey Kardashevskiy         }
908dc1f5988SAlexey Kardashevskiy 
909dc1f5988SAlexey Kardashevskiy         p += sprintf(p, " %.2x", buf[i]);
910dc1f5988SAlexey Kardashevskiy     }
911dc1f5988SAlexey Kardashevskiy }
912dc1f5988SAlexey Kardashevskiy 
913f1ae32a1SGerd Hoffmann /* Service a transport descriptor.
914f1ae32a1SGerd Hoffmann    Returns nonzero to terminate processing of this endpoint.  */
915f1ae32a1SGerd Hoffmann 
916f1ae32a1SGerd Hoffmann static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
917f1ae32a1SGerd Hoffmann {
918f1ae32a1SGerd Hoffmann     int dir;
919f1ae32a1SGerd Hoffmann     size_t len = 0, pktlen = 0;
920f1ae32a1SGerd Hoffmann     const char *str = NULL;
921f1ae32a1SGerd Hoffmann     int pid;
922f1ae32a1SGerd Hoffmann     int ret;
923f1ae32a1SGerd Hoffmann     int i;
924f1ae32a1SGerd Hoffmann     USBDevice *dev;
925f1ae32a1SGerd Hoffmann     USBEndpoint *ep;
926f1ae32a1SGerd Hoffmann     struct ohci_td td;
927f1ae32a1SGerd Hoffmann     uint32_t addr;
928f1ae32a1SGerd Hoffmann     int flag_r;
929f1ae32a1SGerd Hoffmann     int completion;
930f1ae32a1SGerd Hoffmann 
931f1ae32a1SGerd Hoffmann     addr = ed->head & OHCI_DPTR_MASK;
932f1ae32a1SGerd Hoffmann     /* See if this TD has already been submitted to the device.  */
933f1ae32a1SGerd Hoffmann     completion = (addr == ohci->async_td);
934f1ae32a1SGerd Hoffmann     if (completion && !ohci->async_complete) {
935dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_td_skip_async();
936f1ae32a1SGerd Hoffmann         return 1;
937f1ae32a1SGerd Hoffmann     }
938cf66ee8eSAlexey Kardashevskiy     if (ohci_read_td(ohci, addr, &td)) {
939dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_td_read_error(addr);
940cf66ee8eSAlexey Kardashevskiy         ohci_die(ohci);
9416ebc069dSLi Qiang         return 1;
942f1ae32a1SGerd Hoffmann     }
943f1ae32a1SGerd Hoffmann 
944f1ae32a1SGerd Hoffmann     dir = OHCI_BM(ed->flags, ED_D);
945f1ae32a1SGerd Hoffmann     switch (dir) {
946f1ae32a1SGerd Hoffmann     case OHCI_TD_DIR_OUT:
947f1ae32a1SGerd Hoffmann     case OHCI_TD_DIR_IN:
948f1ae32a1SGerd Hoffmann         /* Same value.  */
949f1ae32a1SGerd Hoffmann         break;
950f1ae32a1SGerd Hoffmann     default:
951f1ae32a1SGerd Hoffmann         dir = OHCI_BM(td.flags, TD_DP);
952f1ae32a1SGerd Hoffmann         break;
953f1ae32a1SGerd Hoffmann     }
954f1ae32a1SGerd Hoffmann 
955f1ae32a1SGerd Hoffmann     switch (dir) {
956f1ae32a1SGerd Hoffmann     case OHCI_TD_DIR_IN:
957f1ae32a1SGerd Hoffmann         str = "in";
958f1ae32a1SGerd Hoffmann         pid = USB_TOKEN_IN;
959f1ae32a1SGerd Hoffmann         break;
960f1ae32a1SGerd Hoffmann     case OHCI_TD_DIR_OUT:
961f1ae32a1SGerd Hoffmann         str = "out";
962f1ae32a1SGerd Hoffmann         pid = USB_TOKEN_OUT;
963f1ae32a1SGerd Hoffmann         break;
964f1ae32a1SGerd Hoffmann     case OHCI_TD_DIR_SETUP:
965f1ae32a1SGerd Hoffmann         str = "setup";
966f1ae32a1SGerd Hoffmann         pid = USB_TOKEN_SETUP;
967f1ae32a1SGerd Hoffmann         break;
968f1ae32a1SGerd Hoffmann     default:
969dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_td_bad_direction(dir);
970f1ae32a1SGerd Hoffmann         return 1;
971f1ae32a1SGerd Hoffmann     }
972f1ae32a1SGerd Hoffmann     if (td.cbp && td.be) {
973f1ae32a1SGerd Hoffmann         if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) {
974f1ae32a1SGerd Hoffmann             len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff);
975f1ae32a1SGerd Hoffmann         } else {
976f1ae32a1SGerd Hoffmann             len = (td.be - td.cbp) + 1;
977f1ae32a1SGerd Hoffmann         }
978f1ae32a1SGerd Hoffmann 
979f1ae32a1SGerd Hoffmann         pktlen = len;
980f1ae32a1SGerd Hoffmann         if (len && dir != OHCI_TD_DIR_IN) {
981f1ae32a1SGerd Hoffmann             /* The endpoint may not allow us to transfer it all now */
982f1ae32a1SGerd Hoffmann             pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT;
983f1ae32a1SGerd Hoffmann             if (pktlen > len) {
984f1ae32a1SGerd Hoffmann                 pktlen = len;
985f1ae32a1SGerd Hoffmann             }
986f1ae32a1SGerd Hoffmann             if (!completion) {
987cf66ee8eSAlexey Kardashevskiy                 if (ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen,
988cf66ee8eSAlexey Kardashevskiy                                  DMA_DIRECTION_TO_DEVICE)) {
989cf66ee8eSAlexey Kardashevskiy                     ohci_die(ohci);
990cf66ee8eSAlexey Kardashevskiy                 }
991f1ae32a1SGerd Hoffmann             }
992f1ae32a1SGerd Hoffmann         }
993f1ae32a1SGerd Hoffmann     }
994f1ae32a1SGerd Hoffmann 
995f1ae32a1SGerd Hoffmann     flag_r = (td.flags & OHCI_TD_R) != 0;
996dc1f5988SAlexey Kardashevskiy     trace_usb_ohci_td_pkt_hdr(addr, (int64_t)pktlen, (int64_t)len, str,
997dc1f5988SAlexey Kardashevskiy                               flag_r, td.cbp, td.be);
998dc1f5988SAlexey Kardashevskiy     ohci_td_pkt("OUT", ohci->usb_buf, pktlen);
999f1ae32a1SGerd Hoffmann 
1000f1ae32a1SGerd Hoffmann     if (completion) {
1001f1ae32a1SGerd Hoffmann         ohci->async_td = 0;
100269e25d26SAlexey Kardashevskiy         ohci->async_complete = false;
1003f1ae32a1SGerd Hoffmann     } else {
1004f1ae32a1SGerd Hoffmann         if (ohci->async_td) {
1005f1ae32a1SGerd Hoffmann             /* ??? The hardware should allow one active packet per
1006f1ae32a1SGerd Hoffmann                endpoint.  We only allow one active packet per controller.
1007f1ae32a1SGerd Hoffmann                This should be sufficient as long as devices respond in a
1008f1ae32a1SGerd Hoffmann                timely manner.
1009f1ae32a1SGerd Hoffmann             */
1010dc1f5988SAlexey Kardashevskiy             trace_usb_ohci_td_too_many_pending();
1011f1ae32a1SGerd Hoffmann             return 1;
1012f1ae32a1SGerd Hoffmann         }
1013f1ae32a1SGerd Hoffmann         dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
101442340fc3SLiam Merwick         if (dev == NULL) {
101542340fc3SLiam Merwick             trace_usb_ohci_td_dev_error();
101642340fc3SLiam Merwick             return 1;
101742340fc3SLiam Merwick         }
1018f1ae32a1SGerd Hoffmann         ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
10198550a02dSGerd Hoffmann         usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r,
1020a6fb2ddbSHans de Goede                          OHCI_BM(td.flags, TD_DI) == 0);
1021f1ae32a1SGerd Hoffmann         usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
10229a77a0f5SHans de Goede         usb_handle_packet(dev, &ohci->usb_packet);
1023dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_td_packet_status(ohci->usb_packet.status);
1024dc1f5988SAlexey Kardashevskiy 
10259a77a0f5SHans de Goede         if (ohci->usb_packet.status == USB_RET_ASYNC) {
102636dfe324SHans de Goede             usb_device_flush_ep_queue(dev, ep);
1027f1ae32a1SGerd Hoffmann             ohci->async_td = addr;
1028f1ae32a1SGerd Hoffmann             return 1;
1029f1ae32a1SGerd Hoffmann         }
1030f1ae32a1SGerd Hoffmann     }
10319a77a0f5SHans de Goede     if (ohci->usb_packet.status == USB_RET_SUCCESS) {
10329a77a0f5SHans de Goede         ret = ohci->usb_packet.actual_length;
10339a77a0f5SHans de Goede     } else {
10349a77a0f5SHans de Goede         ret = ohci->usb_packet.status;
10359a77a0f5SHans de Goede     }
10369a77a0f5SHans de Goede 
1037f1ae32a1SGerd Hoffmann     if (ret >= 0) {
1038f1ae32a1SGerd Hoffmann         if (dir == OHCI_TD_DIR_IN) {
1039cf66ee8eSAlexey Kardashevskiy             if (ohci_copy_td(ohci, &td, ohci->usb_buf, ret,
1040cf66ee8eSAlexey Kardashevskiy                              DMA_DIRECTION_FROM_DEVICE)) {
1041cf66ee8eSAlexey Kardashevskiy                 ohci_die(ohci);
1042cf66ee8eSAlexey Kardashevskiy             }
1043dc1f5988SAlexey Kardashevskiy             ohci_td_pkt("IN", ohci->usb_buf, pktlen);
1044f1ae32a1SGerd Hoffmann         } else {
1045f1ae32a1SGerd Hoffmann             ret = pktlen;
1046f1ae32a1SGerd Hoffmann         }
1047f1ae32a1SGerd Hoffmann     }
1048f1ae32a1SGerd Hoffmann 
1049f1ae32a1SGerd Hoffmann     /* Writeback */
1050f1ae32a1SGerd Hoffmann     if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
1051f1ae32a1SGerd Hoffmann         /* Transmission succeeded.  */
1052f1ae32a1SGerd Hoffmann         if (ret == len) {
1053f1ae32a1SGerd Hoffmann             td.cbp = 0;
1054f1ae32a1SGerd Hoffmann         } else {
1055f1ae32a1SGerd Hoffmann             if ((td.cbp & 0xfff) + ret > 0xfff) {
1056f1ae32a1SGerd Hoffmann                 td.cbp = (td.be & ~0xfff) + ((td.cbp + ret) & 0xfff);
1057f1ae32a1SGerd Hoffmann             } else {
1058f1ae32a1SGerd Hoffmann                 td.cbp += ret;
1059f1ae32a1SGerd Hoffmann             }
1060f1ae32a1SGerd Hoffmann         }
1061f1ae32a1SGerd Hoffmann         td.flags |= OHCI_TD_T1;
1062f1ae32a1SGerd Hoffmann         td.flags ^= OHCI_TD_T0;
1063f1ae32a1SGerd Hoffmann         OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR);
1064f1ae32a1SGerd Hoffmann         OHCI_SET_BM(td.flags, TD_EC, 0);
1065f1ae32a1SGerd Hoffmann 
1066f1ae32a1SGerd Hoffmann         if ((dir != OHCI_TD_DIR_IN) && (ret != len)) {
1067f1ae32a1SGerd Hoffmann             /* Partial packet transfer: TD not ready to retire yet */
1068f1ae32a1SGerd Hoffmann             goto exit_no_retire;
1069f1ae32a1SGerd Hoffmann         }
1070f1ae32a1SGerd Hoffmann 
1071f1ae32a1SGerd Hoffmann         /* Setting ED_C is part of the TD retirement process */
1072f1ae32a1SGerd Hoffmann         ed->head &= ~OHCI_ED_C;
1073f1ae32a1SGerd Hoffmann         if (td.flags & OHCI_TD_T0)
1074f1ae32a1SGerd Hoffmann             ed->head |= OHCI_ED_C;
1075f1ae32a1SGerd Hoffmann     } else {
1076f1ae32a1SGerd Hoffmann         if (ret >= 0) {
1077dc1f5988SAlexey Kardashevskiy             trace_usb_ohci_td_underrun();
1078f1ae32a1SGerd Hoffmann             OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN);
1079f1ae32a1SGerd Hoffmann         } else {
1080f1ae32a1SGerd Hoffmann             switch (ret) {
1081f1ae32a1SGerd Hoffmann             case USB_RET_IOERROR:
1082f1ae32a1SGerd Hoffmann             case USB_RET_NODEV:
1083dc1f5988SAlexey Kardashevskiy                 trace_usb_ohci_td_dev_error();
1084f1ae32a1SGerd Hoffmann                 OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING);
10854b351a0fSJán Veselý                 break;
1086f1ae32a1SGerd Hoffmann             case USB_RET_NAK:
1087dc1f5988SAlexey Kardashevskiy                 trace_usb_ohci_td_nak();
1088f1ae32a1SGerd Hoffmann                 return 1;
1089f1ae32a1SGerd Hoffmann             case USB_RET_STALL:
1090dc1f5988SAlexey Kardashevskiy                 trace_usb_ohci_td_stall();
1091f1ae32a1SGerd Hoffmann                 OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL);
1092f1ae32a1SGerd Hoffmann                 break;
1093f1ae32a1SGerd Hoffmann             case USB_RET_BABBLE:
1094dc1f5988SAlexey Kardashevskiy                 trace_usb_ohci_td_babble();
1095f1ae32a1SGerd Hoffmann                 OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
1096f1ae32a1SGerd Hoffmann                 break;
1097f1ae32a1SGerd Hoffmann             default:
1098dc1f5988SAlexey Kardashevskiy                 trace_usb_ohci_td_bad_device_response(ret);
1099f1ae32a1SGerd Hoffmann                 OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID);
1100f1ae32a1SGerd Hoffmann                 OHCI_SET_BM(td.flags, TD_EC, 3);
1101f1ae32a1SGerd Hoffmann                 break;
1102f1ae32a1SGerd Hoffmann             }
11037c48b95dSSebastian Bauer             /* An error occured so we have to clear the interrupt counter. See
11047c48b95dSSebastian Bauer              * spec at 6.4.4 on page 104 */
11057c48b95dSSebastian Bauer             ohci->done_count = 0;
1106f1ae32a1SGerd Hoffmann         }
1107f1ae32a1SGerd Hoffmann         ed->head |= OHCI_ED_H;
1108f1ae32a1SGerd Hoffmann     }
1109f1ae32a1SGerd Hoffmann 
1110f1ae32a1SGerd Hoffmann     /* Retire this TD */
1111f1ae32a1SGerd Hoffmann     ed->head &= ~OHCI_DPTR_MASK;
1112f1ae32a1SGerd Hoffmann     ed->head |= td.next & OHCI_DPTR_MASK;
1113f1ae32a1SGerd Hoffmann     td.next = ohci->done;
1114f1ae32a1SGerd Hoffmann     ohci->done = addr;
1115f1ae32a1SGerd Hoffmann     i = OHCI_BM(td.flags, TD_DI);
1116f1ae32a1SGerd Hoffmann     if (i < ohci->done_count)
1117f1ae32a1SGerd Hoffmann         ohci->done_count = i;
1118f1ae32a1SGerd Hoffmann exit_no_retire:
1119cf66ee8eSAlexey Kardashevskiy     if (ohci_put_td(ohci, addr, &td)) {
1120cf66ee8eSAlexey Kardashevskiy         ohci_die(ohci);
1121cf66ee8eSAlexey Kardashevskiy         return 1;
1122cf66ee8eSAlexey Kardashevskiy     }
1123f1ae32a1SGerd Hoffmann     return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
1124f1ae32a1SGerd Hoffmann }
1125f1ae32a1SGerd Hoffmann 
1126f1ae32a1SGerd Hoffmann /* Service an endpoint list.  Returns nonzero if active TD were found.  */
1127f1ae32a1SGerd Hoffmann static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
1128f1ae32a1SGerd Hoffmann {
1129f1ae32a1SGerd Hoffmann     struct ohci_ed ed;
1130f1ae32a1SGerd Hoffmann     uint32_t next_ed;
1131f1ae32a1SGerd Hoffmann     uint32_t cur;
1132f1ae32a1SGerd Hoffmann     int active;
113395ed5693SLi Qiang     uint32_t link_cnt = 0;
1134f1ae32a1SGerd Hoffmann     active = 0;
1135f1ae32a1SGerd Hoffmann 
1136f1ae32a1SGerd Hoffmann     if (head == 0)
1137f1ae32a1SGerd Hoffmann         return 0;
1138f1ae32a1SGerd Hoffmann 
1139ab878998SLaurent Vivier     for (cur = head; cur && link_cnt++ < ED_LINK_LIMIT; cur = next_ed) {
1140cf66ee8eSAlexey Kardashevskiy         if (ohci_read_ed(ohci, cur, &ed)) {
1141dc1f5988SAlexey Kardashevskiy             trace_usb_ohci_ed_read_error(cur);
1142cf66ee8eSAlexey Kardashevskiy             ohci_die(ohci);
1143f1ae32a1SGerd Hoffmann             return 0;
1144f1ae32a1SGerd Hoffmann         }
1145f1ae32a1SGerd Hoffmann 
1146f1ae32a1SGerd Hoffmann         next_ed = ed.next & OHCI_DPTR_MASK;
1147f1ae32a1SGerd Hoffmann 
1148f1ae32a1SGerd Hoffmann         if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) {
1149f1ae32a1SGerd Hoffmann             uint32_t addr;
1150f1ae32a1SGerd Hoffmann             /* Cancel pending packets for ED that have been paused.  */
1151f1ae32a1SGerd Hoffmann             addr = ed.head & OHCI_DPTR_MASK;
1152f1ae32a1SGerd Hoffmann             if (ohci->async_td && addr == ohci->async_td) {
1153f1ae32a1SGerd Hoffmann                 usb_cancel_packet(&ohci->usb_packet);
1154f1ae32a1SGerd Hoffmann                 ohci->async_td = 0;
1155f79738b0SHans de Goede                 usb_device_ep_stopped(ohci->usb_packet.ep->dev,
1156f79738b0SHans de Goede                                       ohci->usb_packet.ep);
1157f1ae32a1SGerd Hoffmann             }
1158f1ae32a1SGerd Hoffmann             continue;
1159f1ae32a1SGerd Hoffmann         }
1160f1ae32a1SGerd Hoffmann 
1161f1ae32a1SGerd Hoffmann         while ((ed.head & OHCI_DPTR_MASK) != ed.tail) {
11623af8f177SAlexey Kardashevskiy             trace_usb_ohci_ed_pkt(cur, (ed.head & OHCI_ED_H) != 0,
11633af8f177SAlexey Kardashevskiy                     (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK,
11643af8f177SAlexey Kardashevskiy                     ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK);
11653af8f177SAlexey Kardashevskiy             trace_usb_ohci_ed_pkt_flags(
1166f1ae32a1SGerd Hoffmann                     OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN),
1167f1ae32a1SGerd Hoffmann                     OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0,
1168f1ae32a1SGerd Hoffmann                     (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0,
11693af8f177SAlexey Kardashevskiy                     OHCI_BM(ed.flags, ED_MPS));
1170dc1f5988SAlexey Kardashevskiy 
1171f1ae32a1SGerd Hoffmann             active = 1;
1172f1ae32a1SGerd Hoffmann 
1173f1ae32a1SGerd Hoffmann             if ((ed.flags & OHCI_ED_F) == 0) {
1174f1ae32a1SGerd Hoffmann                 if (ohci_service_td(ohci, &ed))
1175f1ae32a1SGerd Hoffmann                     break;
1176f1ae32a1SGerd Hoffmann             } else {
1177f1ae32a1SGerd Hoffmann                 /* Handle isochronous endpoints */
1178f1ae32a1SGerd Hoffmann                 if (ohci_service_iso_td(ohci, &ed, completion))
1179f1ae32a1SGerd Hoffmann                     break;
1180f1ae32a1SGerd Hoffmann             }
1181f1ae32a1SGerd Hoffmann         }
1182f1ae32a1SGerd Hoffmann 
1183cf66ee8eSAlexey Kardashevskiy         if (ohci_put_ed(ohci, cur, &ed)) {
1184cf66ee8eSAlexey Kardashevskiy             ohci_die(ohci);
1185cf66ee8eSAlexey Kardashevskiy             return 0;
1186cf66ee8eSAlexey Kardashevskiy         }
1187f1ae32a1SGerd Hoffmann     }
1188f1ae32a1SGerd Hoffmann 
1189f1ae32a1SGerd Hoffmann     return active;
1190f1ae32a1SGerd Hoffmann }
1191f1ae32a1SGerd Hoffmann 
1192fd0a10cdSLaurent Vivier /* set a timer for EOF */
1193fd0a10cdSLaurent Vivier static void ohci_eof_timer(OHCIState *ohci)
1194f1ae32a1SGerd Hoffmann {
1195bc72ad67SAlex Bligh     timer_mod(ohci->eof_timer, ohci->sof_time + usb_frame_time);
1196fd0a10cdSLaurent Vivier }
1197fd0a10cdSLaurent Vivier /* Set a timer for EOF and generate a SOF event */
1198fd0a10cdSLaurent Vivier static void ohci_sof(OHCIState *ohci)
1199fd0a10cdSLaurent Vivier {
1200a60f39a4SMiguel GAIO     ohci->sof_time += usb_frame_time;
1201fd0a10cdSLaurent Vivier     ohci_eof_timer(ohci);
1202f1ae32a1SGerd Hoffmann     ohci_set_interrupt(ohci, OHCI_INTR_SF);
1203f1ae32a1SGerd Hoffmann }
1204f1ae32a1SGerd Hoffmann 
1205f1ae32a1SGerd Hoffmann /* Process Control and Bulk lists.  */
1206f1ae32a1SGerd Hoffmann static void ohci_process_lists(OHCIState *ohci, int completion)
1207f1ae32a1SGerd Hoffmann {
1208f1ae32a1SGerd Hoffmann     if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
1209f1ae32a1SGerd Hoffmann         if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) {
1210dc1f5988SAlexey Kardashevskiy             trace_usb_ohci_process_lists(ohci->ctrl_head, ohci->ctrl_cur);
1211f1ae32a1SGerd Hoffmann         }
1212f1ae32a1SGerd Hoffmann         if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) {
1213f1ae32a1SGerd Hoffmann             ohci->ctrl_cur = 0;
1214f1ae32a1SGerd Hoffmann             ohci->status &= ~OHCI_STATUS_CLF;
1215f1ae32a1SGerd Hoffmann         }
1216f1ae32a1SGerd Hoffmann     }
1217f1ae32a1SGerd Hoffmann 
1218f1ae32a1SGerd Hoffmann     if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) {
1219f1ae32a1SGerd Hoffmann         if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) {
1220f1ae32a1SGerd Hoffmann             ohci->bulk_cur = 0;
1221f1ae32a1SGerd Hoffmann             ohci->status &= ~OHCI_STATUS_BLF;
1222f1ae32a1SGerd Hoffmann         }
1223f1ae32a1SGerd Hoffmann     }
1224f1ae32a1SGerd Hoffmann }
1225f1ae32a1SGerd Hoffmann 
1226f1ae32a1SGerd Hoffmann /* Do frame processing on frame boundary */
1227f1ae32a1SGerd Hoffmann static void ohci_frame_boundary(void *opaque)
1228f1ae32a1SGerd Hoffmann {
1229f1ae32a1SGerd Hoffmann     OHCIState *ohci = opaque;
1230f1ae32a1SGerd Hoffmann     struct ohci_hcca hcca;
1231f1ae32a1SGerd Hoffmann 
1232cf66ee8eSAlexey Kardashevskiy     if (ohci_read_hcca(ohci, ohci->hcca, &hcca)) {
1233dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_hcca_read_error(ohci->hcca);
1234cf66ee8eSAlexey Kardashevskiy         ohci_die(ohci);
1235cf66ee8eSAlexey Kardashevskiy         return;
1236cf66ee8eSAlexey Kardashevskiy     }
1237f1ae32a1SGerd Hoffmann 
1238f1ae32a1SGerd Hoffmann     /* Process all the lists at the end of the frame */
1239f1ae32a1SGerd Hoffmann     if (ohci->ctl & OHCI_CTL_PLE) {
1240f1ae32a1SGerd Hoffmann         int n;
1241f1ae32a1SGerd Hoffmann 
1242f1ae32a1SGerd Hoffmann         n = ohci->frame_number & 0x1f;
1243f1ae32a1SGerd Hoffmann         ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0);
1244f1ae32a1SGerd Hoffmann     }
1245f1ae32a1SGerd Hoffmann 
1246f1ae32a1SGerd Hoffmann     /* Cancel all pending packets if either of the lists has been disabled.  */
1247f79738b0SHans de Goede     if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
1248f79738b0SHans de Goede         if (ohci->async_td) {
1249f1ae32a1SGerd Hoffmann             usb_cancel_packet(&ohci->usb_packet);
1250f1ae32a1SGerd Hoffmann             ohci->async_td = 0;
1251f1ae32a1SGerd Hoffmann         }
1252f79738b0SHans de Goede         ohci_stop_endpoints(ohci);
1253f79738b0SHans de Goede     }
1254f1ae32a1SGerd Hoffmann     ohci->old_ctl = ohci->ctl;
1255f1ae32a1SGerd Hoffmann     ohci_process_lists(ohci, 0);
1256f1ae32a1SGerd Hoffmann 
1257cf66ee8eSAlexey Kardashevskiy     /* Stop if UnrecoverableError happened or ohci_sof will crash */
1258cf66ee8eSAlexey Kardashevskiy     if (ohci->intr_status & OHCI_INTR_UE) {
1259cf66ee8eSAlexey Kardashevskiy         return;
1260cf66ee8eSAlexey Kardashevskiy     }
1261cf66ee8eSAlexey Kardashevskiy 
1262f1ae32a1SGerd Hoffmann     /* Frame boundary, so do EOF stuf here */
1263f1ae32a1SGerd Hoffmann     ohci->frt = ohci->fit;
1264f1ae32a1SGerd Hoffmann 
1265f1ae32a1SGerd Hoffmann     /* Increment frame number and take care of endianness. */
1266f1ae32a1SGerd Hoffmann     ohci->frame_number = (ohci->frame_number + 1) & 0xffff;
1267f1ae32a1SGerd Hoffmann     hcca.frame = cpu_to_le16(ohci->frame_number);
1268f1ae32a1SGerd Hoffmann 
1269f1ae32a1SGerd Hoffmann     if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) {
1270f1ae32a1SGerd Hoffmann         if (!ohci->done)
1271f1ae32a1SGerd Hoffmann             abort();
1272f1ae32a1SGerd Hoffmann         if (ohci->intr & ohci->intr_status)
1273f1ae32a1SGerd Hoffmann             ohci->done |= 1;
1274f1ae32a1SGerd Hoffmann         hcca.done = cpu_to_le32(ohci->done);
1275f1ae32a1SGerd Hoffmann         ohci->done = 0;
1276f1ae32a1SGerd Hoffmann         ohci->done_count = 7;
1277f1ae32a1SGerd Hoffmann         ohci_set_interrupt(ohci, OHCI_INTR_WD);
1278f1ae32a1SGerd Hoffmann     }
1279f1ae32a1SGerd Hoffmann 
1280f1ae32a1SGerd Hoffmann     if (ohci->done_count != 7 && ohci->done_count != 0)
1281f1ae32a1SGerd Hoffmann         ohci->done_count--;
1282f1ae32a1SGerd Hoffmann 
1283f1ae32a1SGerd Hoffmann     /* Do SOF stuff here */
1284f1ae32a1SGerd Hoffmann     ohci_sof(ohci);
1285f1ae32a1SGerd Hoffmann 
1286f1ae32a1SGerd Hoffmann     /* Writeback HCCA */
1287cf66ee8eSAlexey Kardashevskiy     if (ohci_put_hcca(ohci, ohci->hcca, &hcca)) {
1288cf66ee8eSAlexey Kardashevskiy         ohci_die(ohci);
1289cf66ee8eSAlexey Kardashevskiy     }
1290f1ae32a1SGerd Hoffmann }
1291f1ae32a1SGerd Hoffmann 
1292f1ae32a1SGerd Hoffmann /* Start sending SOF tokens across the USB bus, lists are processed in
1293f1ae32a1SGerd Hoffmann  * next frame
1294f1ae32a1SGerd Hoffmann  */
1295f1ae32a1SGerd Hoffmann static int ohci_bus_start(OHCIState *ohci)
1296f1ae32a1SGerd Hoffmann {
1297dc1f5988SAlexey Kardashevskiy     trace_usb_ohci_start(ohci->name);
1298f1ae32a1SGerd Hoffmann 
1299fd0a10cdSLaurent Vivier     /* Delay the first SOF event by one frame time as
1300fd0a10cdSLaurent Vivier      * linux driver is not ready to receive it and
1301fd0a10cdSLaurent Vivier      * can meet some race conditions
1302fd0a10cdSLaurent Vivier      */
1303fd0a10cdSLaurent Vivier 
1304a60f39a4SMiguel GAIO     ohci->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1305fd0a10cdSLaurent Vivier     ohci_eof_timer(ohci);
1306f1ae32a1SGerd Hoffmann 
1307f1ae32a1SGerd Hoffmann     return 1;
1308f1ae32a1SGerd Hoffmann }
1309f1ae32a1SGerd Hoffmann 
1310f1ae32a1SGerd Hoffmann /* Stop sending SOF tokens on the bus */
131134d97308SThomas Huth void ohci_bus_stop(OHCIState *ohci)
1312f1ae32a1SGerd Hoffmann {
1313dc1f5988SAlexey Kardashevskiy     trace_usb_ohci_stop(ohci->name);
1314bc72ad67SAlex Bligh     timer_del(ohci->eof_timer);
1315f1ae32a1SGerd Hoffmann }
1316f1ae32a1SGerd Hoffmann 
1317f1ae32a1SGerd Hoffmann /* Sets a flag in a port status register but only set it if the port is
1318f1ae32a1SGerd Hoffmann  * connected, if not set ConnectStatusChange flag. If flag is enabled
1319f1ae32a1SGerd Hoffmann  * return 1.
1320f1ae32a1SGerd Hoffmann  */
1321f1ae32a1SGerd Hoffmann static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val)
1322f1ae32a1SGerd Hoffmann {
1323f1ae32a1SGerd Hoffmann     int ret = 1;
1324f1ae32a1SGerd Hoffmann 
1325f1ae32a1SGerd Hoffmann     /* writing a 0 has no effect */
1326f1ae32a1SGerd Hoffmann     if (val == 0)
1327f1ae32a1SGerd Hoffmann         return 0;
1328f1ae32a1SGerd Hoffmann 
1329f1ae32a1SGerd Hoffmann     /* If CurrentConnectStatus is cleared we set
1330f1ae32a1SGerd Hoffmann      * ConnectStatusChange
1331f1ae32a1SGerd Hoffmann      */
1332f1ae32a1SGerd Hoffmann     if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) {
1333f1ae32a1SGerd Hoffmann         ohci->rhport[i].ctrl |= OHCI_PORT_CSC;
1334f1ae32a1SGerd Hoffmann         if (ohci->rhstatus & OHCI_RHS_DRWE) {
1335f1ae32a1SGerd Hoffmann             /* TODO: CSC is a wakeup event */
1336f1ae32a1SGerd Hoffmann         }
1337f1ae32a1SGerd Hoffmann         return 0;
1338f1ae32a1SGerd Hoffmann     }
1339f1ae32a1SGerd Hoffmann 
1340f1ae32a1SGerd Hoffmann     if (ohci->rhport[i].ctrl & val)
1341f1ae32a1SGerd Hoffmann         ret = 0;
1342f1ae32a1SGerd Hoffmann 
1343f1ae32a1SGerd Hoffmann     /* set the bit */
1344f1ae32a1SGerd Hoffmann     ohci->rhport[i].ctrl |= val;
1345f1ae32a1SGerd Hoffmann 
1346f1ae32a1SGerd Hoffmann     return ret;
1347f1ae32a1SGerd Hoffmann }
1348f1ae32a1SGerd Hoffmann 
1349f1ae32a1SGerd Hoffmann /* Set the frame interval - frame interval toggle is manipulated by the hcd only */
1350f1ae32a1SGerd Hoffmann static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val)
1351f1ae32a1SGerd Hoffmann {
1352f1ae32a1SGerd Hoffmann     val &= OHCI_FMI_FI;
1353f1ae32a1SGerd Hoffmann 
1354f1ae32a1SGerd Hoffmann     if (val != ohci->fi) {
1355dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_set_frame_interval(ohci->name, ohci->fi, ohci->fi);
1356f1ae32a1SGerd Hoffmann     }
1357f1ae32a1SGerd Hoffmann 
1358f1ae32a1SGerd Hoffmann     ohci->fi = val;
1359f1ae32a1SGerd Hoffmann }
1360f1ae32a1SGerd Hoffmann 
1361f1ae32a1SGerd Hoffmann static void ohci_port_power(OHCIState *ohci, int i, int p)
1362f1ae32a1SGerd Hoffmann {
1363f1ae32a1SGerd Hoffmann     if (p) {
1364f1ae32a1SGerd Hoffmann         ohci->rhport[i].ctrl |= OHCI_PORT_PPS;
1365f1ae32a1SGerd Hoffmann     } else {
1366f1ae32a1SGerd Hoffmann         ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS|
1367f1ae32a1SGerd Hoffmann                     OHCI_PORT_CCS|
1368f1ae32a1SGerd Hoffmann                     OHCI_PORT_PSS|
1369f1ae32a1SGerd Hoffmann                     OHCI_PORT_PRS);
1370f1ae32a1SGerd Hoffmann     }
1371f1ae32a1SGerd Hoffmann }
1372f1ae32a1SGerd Hoffmann 
1373f1ae32a1SGerd Hoffmann /* Set HcControlRegister */
1374f1ae32a1SGerd Hoffmann static void ohci_set_ctl(OHCIState *ohci, uint32_t val)
1375f1ae32a1SGerd Hoffmann {
1376f1ae32a1SGerd Hoffmann     uint32_t old_state;
1377f1ae32a1SGerd Hoffmann     uint32_t new_state;
1378f1ae32a1SGerd Hoffmann 
1379f1ae32a1SGerd Hoffmann     old_state = ohci->ctl & OHCI_CTL_HCFS;
1380f1ae32a1SGerd Hoffmann     ohci->ctl = val;
1381f1ae32a1SGerd Hoffmann     new_state = ohci->ctl & OHCI_CTL_HCFS;
1382f1ae32a1SGerd Hoffmann 
1383f1ae32a1SGerd Hoffmann     /* no state change */
1384f1ae32a1SGerd Hoffmann     if (old_state == new_state)
1385f1ae32a1SGerd Hoffmann         return;
1386f1ae32a1SGerd Hoffmann 
1387dc1f5988SAlexey Kardashevskiy     trace_usb_ohci_set_ctl(ohci->name, new_state);
1388f1ae32a1SGerd Hoffmann     switch (new_state) {
1389f1ae32a1SGerd Hoffmann     case OHCI_USB_OPERATIONAL:
1390f1ae32a1SGerd Hoffmann         ohci_bus_start(ohci);
1391f1ae32a1SGerd Hoffmann         break;
1392f1ae32a1SGerd Hoffmann     case OHCI_USB_SUSPEND:
1393f1ae32a1SGerd Hoffmann         ohci_bus_stop(ohci);
1394087462c7SLaurent Vivier         /* clear pending SF otherwise linux driver loops in ohci_irq() */
1395087462c7SLaurent Vivier         ohci->intr_status &= ~OHCI_INTR_SF;
1396087462c7SLaurent Vivier         ohci_intr_update(ohci);
1397f1ae32a1SGerd Hoffmann         break;
1398f1ae32a1SGerd Hoffmann     case OHCI_USB_RESUME:
1399dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_resume(ohci->name);
1400f1ae32a1SGerd Hoffmann         break;
1401f1ae32a1SGerd Hoffmann     case OHCI_USB_RESET:
14027d938fd1SHervé Poussineau         ohci_roothub_reset(ohci);
1403f1ae32a1SGerd Hoffmann         break;
1404f1ae32a1SGerd Hoffmann     }
1405f1ae32a1SGerd Hoffmann }
1406f1ae32a1SGerd Hoffmann 
1407f1ae32a1SGerd Hoffmann static uint32_t ohci_get_frame_remaining(OHCIState *ohci)
1408f1ae32a1SGerd Hoffmann {
1409f1ae32a1SGerd Hoffmann     uint16_t fr;
1410f1ae32a1SGerd Hoffmann     int64_t tks;
1411f1ae32a1SGerd Hoffmann 
1412f1ae32a1SGerd Hoffmann     if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL)
1413f1ae32a1SGerd Hoffmann         return (ohci->frt << 31);
1414f1ae32a1SGerd Hoffmann 
1415f1ae32a1SGerd Hoffmann     /* Being in USB operational state guarnatees sof_time was
1416f1ae32a1SGerd Hoffmann      * set already.
1417f1ae32a1SGerd Hoffmann      */
1418bc72ad67SAlex Bligh     tks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - ohci->sof_time;
1419a60f39a4SMiguel GAIO     if (tks < 0) {
1420a60f39a4SMiguel GAIO         tks = 0;
1421a60f39a4SMiguel GAIO     }
1422f1ae32a1SGerd Hoffmann 
1423f1ae32a1SGerd Hoffmann     /* avoid muldiv if possible */
1424f1ae32a1SGerd Hoffmann     if (tks >= usb_frame_time)
1425f1ae32a1SGerd Hoffmann         return (ohci->frt << 31);
1426f1ae32a1SGerd Hoffmann 
1427cd1f16f9SLaurent Vivier     tks = tks / usb_bit_time;
1428f1ae32a1SGerd Hoffmann     fr = (uint16_t)(ohci->fi - tks);
1429f1ae32a1SGerd Hoffmann 
1430f1ae32a1SGerd Hoffmann     return (ohci->frt << 31) | fr;
1431f1ae32a1SGerd Hoffmann }
1432f1ae32a1SGerd Hoffmann 
1433f1ae32a1SGerd Hoffmann 
1434f1ae32a1SGerd Hoffmann /* Set root hub status */
1435f1ae32a1SGerd Hoffmann static void ohci_set_hub_status(OHCIState *ohci, uint32_t val)
1436f1ae32a1SGerd Hoffmann {
1437f1ae32a1SGerd Hoffmann     uint32_t old_state;
1438f1ae32a1SGerd Hoffmann 
1439f1ae32a1SGerd Hoffmann     old_state = ohci->rhstatus;
1440f1ae32a1SGerd Hoffmann 
1441f1ae32a1SGerd Hoffmann     /* write 1 to clear OCIC */
1442f1ae32a1SGerd Hoffmann     if (val & OHCI_RHS_OCIC)
1443f1ae32a1SGerd Hoffmann         ohci->rhstatus &= ~OHCI_RHS_OCIC;
1444f1ae32a1SGerd Hoffmann 
1445f1ae32a1SGerd Hoffmann     if (val & OHCI_RHS_LPS) {
1446f1ae32a1SGerd Hoffmann         int i;
1447f1ae32a1SGerd Hoffmann 
1448f1ae32a1SGerd Hoffmann         for (i = 0; i < ohci->num_ports; i++)
1449f1ae32a1SGerd Hoffmann             ohci_port_power(ohci, i, 0);
1450dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_hub_power_down();
1451f1ae32a1SGerd Hoffmann     }
1452f1ae32a1SGerd Hoffmann 
1453f1ae32a1SGerd Hoffmann     if (val & OHCI_RHS_LPSC) {
1454f1ae32a1SGerd Hoffmann         int i;
1455f1ae32a1SGerd Hoffmann 
1456f1ae32a1SGerd Hoffmann         for (i = 0; i < ohci->num_ports; i++)
1457f1ae32a1SGerd Hoffmann             ohci_port_power(ohci, i, 1);
1458dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_hub_power_up();
1459f1ae32a1SGerd Hoffmann     }
1460f1ae32a1SGerd Hoffmann 
1461f1ae32a1SGerd Hoffmann     if (val & OHCI_RHS_DRWE)
1462f1ae32a1SGerd Hoffmann         ohci->rhstatus |= OHCI_RHS_DRWE;
1463f1ae32a1SGerd Hoffmann 
1464f1ae32a1SGerd Hoffmann     if (val & OHCI_RHS_CRWE)
1465f1ae32a1SGerd Hoffmann         ohci->rhstatus &= ~OHCI_RHS_DRWE;
1466f1ae32a1SGerd Hoffmann 
1467f1ae32a1SGerd Hoffmann     if (old_state != ohci->rhstatus)
1468f1ae32a1SGerd Hoffmann         ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
1469f1ae32a1SGerd Hoffmann }
1470f1ae32a1SGerd Hoffmann 
1471f1ae32a1SGerd Hoffmann /* Set root hub port status */
1472f1ae32a1SGerd Hoffmann static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
1473f1ae32a1SGerd Hoffmann {
1474f1ae32a1SGerd Hoffmann     uint32_t old_state;
1475f1ae32a1SGerd Hoffmann     OHCIPort *port;
1476f1ae32a1SGerd Hoffmann 
1477f1ae32a1SGerd Hoffmann     port = &ohci->rhport[portnum];
1478f1ae32a1SGerd Hoffmann     old_state = port->ctrl;
1479f1ae32a1SGerd Hoffmann 
1480f1ae32a1SGerd Hoffmann     /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */
1481f1ae32a1SGerd Hoffmann     if (val & OHCI_PORT_WTC)
1482f1ae32a1SGerd Hoffmann         port->ctrl &= ~(val & OHCI_PORT_WTC);
1483f1ae32a1SGerd Hoffmann 
1484f1ae32a1SGerd Hoffmann     if (val & OHCI_PORT_CCS)
1485f1ae32a1SGerd Hoffmann         port->ctrl &= ~OHCI_PORT_PES;
1486f1ae32a1SGerd Hoffmann 
1487f1ae32a1SGerd Hoffmann     ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES);
1488f1ae32a1SGerd Hoffmann 
1489f1ae32a1SGerd Hoffmann     if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) {
1490dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_port_suspend(portnum);
1491f1ae32a1SGerd Hoffmann     }
1492f1ae32a1SGerd Hoffmann 
1493f1ae32a1SGerd Hoffmann     if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) {
1494dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_port_reset(portnum);
1495f1ae32a1SGerd Hoffmann         usb_device_reset(port->port.dev);
1496f1ae32a1SGerd Hoffmann         port->ctrl &= ~OHCI_PORT_PRS;
1497f1ae32a1SGerd Hoffmann         /* ??? Should this also set OHCI_PORT_PESC.  */
1498f1ae32a1SGerd Hoffmann         port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC;
1499f1ae32a1SGerd Hoffmann     }
1500f1ae32a1SGerd Hoffmann 
1501f1ae32a1SGerd Hoffmann     /* Invert order here to ensure in ambiguous case, device is
1502f1ae32a1SGerd Hoffmann      * powered up...
1503f1ae32a1SGerd Hoffmann      */
1504f1ae32a1SGerd Hoffmann     if (val & OHCI_PORT_LSDA)
1505f1ae32a1SGerd Hoffmann         ohci_port_power(ohci, portnum, 0);
1506f1ae32a1SGerd Hoffmann     if (val & OHCI_PORT_PPS)
1507f1ae32a1SGerd Hoffmann         ohci_port_power(ohci, portnum, 1);
1508f1ae32a1SGerd Hoffmann 
1509f1ae32a1SGerd Hoffmann     if (old_state != port->ctrl)
1510f1ae32a1SGerd Hoffmann         ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
1511f1ae32a1SGerd Hoffmann }
1512f1ae32a1SGerd Hoffmann 
1513f1ae32a1SGerd Hoffmann static uint64_t ohci_mem_read(void *opaque,
1514a8170e5eSAvi Kivity                               hwaddr addr,
1515f1ae32a1SGerd Hoffmann                               unsigned size)
1516f1ae32a1SGerd Hoffmann {
1517f1ae32a1SGerd Hoffmann     OHCIState *ohci = opaque;
1518f1ae32a1SGerd Hoffmann     uint32_t retval;
1519f1ae32a1SGerd Hoffmann 
1520f1ae32a1SGerd Hoffmann     /* Only aligned reads are allowed on OHCI */
1521f1ae32a1SGerd Hoffmann     if (addr & 3) {
1522dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_mem_read_unaligned(addr);
1523f1ae32a1SGerd Hoffmann         return 0xffffffff;
1524f1ae32a1SGerd Hoffmann     } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
1525f1ae32a1SGerd Hoffmann         /* HcRhPortStatus */
1526f1ae32a1SGerd Hoffmann         retval = ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS;
1527f1ae32a1SGerd Hoffmann     } else {
1528f1ae32a1SGerd Hoffmann         switch (addr >> 2) {
1529f1ae32a1SGerd Hoffmann         case 0: /* HcRevision */
1530f1ae32a1SGerd Hoffmann             retval = 0x10;
1531f1ae32a1SGerd Hoffmann             break;
1532f1ae32a1SGerd Hoffmann 
1533f1ae32a1SGerd Hoffmann         case 1: /* HcControl */
1534f1ae32a1SGerd Hoffmann             retval = ohci->ctl;
1535f1ae32a1SGerd Hoffmann             break;
1536f1ae32a1SGerd Hoffmann 
1537f1ae32a1SGerd Hoffmann         case 2: /* HcCommandStatus */
1538f1ae32a1SGerd Hoffmann             retval = ohci->status;
1539f1ae32a1SGerd Hoffmann             break;
1540f1ae32a1SGerd Hoffmann 
1541f1ae32a1SGerd Hoffmann         case 3: /* HcInterruptStatus */
1542f1ae32a1SGerd Hoffmann             retval = ohci->intr_status;
1543f1ae32a1SGerd Hoffmann             break;
1544f1ae32a1SGerd Hoffmann 
1545f1ae32a1SGerd Hoffmann         case 4: /* HcInterruptEnable */
1546f1ae32a1SGerd Hoffmann         case 5: /* HcInterruptDisable */
1547f1ae32a1SGerd Hoffmann             retval = ohci->intr;
1548f1ae32a1SGerd Hoffmann             break;
1549f1ae32a1SGerd Hoffmann 
1550f1ae32a1SGerd Hoffmann         case 6: /* HcHCCA */
1551f1ae32a1SGerd Hoffmann             retval = ohci->hcca;
1552f1ae32a1SGerd Hoffmann             break;
1553f1ae32a1SGerd Hoffmann 
1554f1ae32a1SGerd Hoffmann         case 7: /* HcPeriodCurrentED */
1555f1ae32a1SGerd Hoffmann             retval = ohci->per_cur;
1556f1ae32a1SGerd Hoffmann             break;
1557f1ae32a1SGerd Hoffmann 
1558f1ae32a1SGerd Hoffmann         case 8: /* HcControlHeadED */
1559f1ae32a1SGerd Hoffmann             retval = ohci->ctrl_head;
1560f1ae32a1SGerd Hoffmann             break;
1561f1ae32a1SGerd Hoffmann 
1562f1ae32a1SGerd Hoffmann         case 9: /* HcControlCurrentED */
1563f1ae32a1SGerd Hoffmann             retval = ohci->ctrl_cur;
1564f1ae32a1SGerd Hoffmann             break;
1565f1ae32a1SGerd Hoffmann 
1566f1ae32a1SGerd Hoffmann         case 10: /* HcBulkHeadED */
1567f1ae32a1SGerd Hoffmann             retval = ohci->bulk_head;
1568f1ae32a1SGerd Hoffmann             break;
1569f1ae32a1SGerd Hoffmann 
1570f1ae32a1SGerd Hoffmann         case 11: /* HcBulkCurrentED */
1571f1ae32a1SGerd Hoffmann             retval = ohci->bulk_cur;
1572f1ae32a1SGerd Hoffmann             break;
1573f1ae32a1SGerd Hoffmann 
1574f1ae32a1SGerd Hoffmann         case 12: /* HcDoneHead */
1575f1ae32a1SGerd Hoffmann             retval = ohci->done;
1576f1ae32a1SGerd Hoffmann             break;
1577f1ae32a1SGerd Hoffmann 
1578f1ae32a1SGerd Hoffmann         case 13: /* HcFmInterretval */
1579f1ae32a1SGerd Hoffmann             retval = (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi);
1580f1ae32a1SGerd Hoffmann             break;
1581f1ae32a1SGerd Hoffmann 
1582f1ae32a1SGerd Hoffmann         case 14: /* HcFmRemaining */
1583f1ae32a1SGerd Hoffmann             retval = ohci_get_frame_remaining(ohci);
1584f1ae32a1SGerd Hoffmann             break;
1585f1ae32a1SGerd Hoffmann 
1586f1ae32a1SGerd Hoffmann         case 15: /* HcFmNumber */
1587f1ae32a1SGerd Hoffmann             retval = ohci->frame_number;
1588f1ae32a1SGerd Hoffmann             break;
1589f1ae32a1SGerd Hoffmann 
1590f1ae32a1SGerd Hoffmann         case 16: /* HcPeriodicStart */
1591f1ae32a1SGerd Hoffmann             retval = ohci->pstart;
1592f1ae32a1SGerd Hoffmann             break;
1593f1ae32a1SGerd Hoffmann 
1594f1ae32a1SGerd Hoffmann         case 17: /* HcLSThreshold */
1595f1ae32a1SGerd Hoffmann             retval = ohci->lst;
1596f1ae32a1SGerd Hoffmann             break;
1597f1ae32a1SGerd Hoffmann 
1598f1ae32a1SGerd Hoffmann         case 18: /* HcRhDescriptorA */
1599f1ae32a1SGerd Hoffmann             retval = ohci->rhdesc_a;
1600f1ae32a1SGerd Hoffmann             break;
1601f1ae32a1SGerd Hoffmann 
1602f1ae32a1SGerd Hoffmann         case 19: /* HcRhDescriptorB */
1603f1ae32a1SGerd Hoffmann             retval = ohci->rhdesc_b;
1604f1ae32a1SGerd Hoffmann             break;
1605f1ae32a1SGerd Hoffmann 
1606f1ae32a1SGerd Hoffmann         case 20: /* HcRhStatus */
1607f1ae32a1SGerd Hoffmann             retval = ohci->rhstatus;
1608f1ae32a1SGerd Hoffmann             break;
1609f1ae32a1SGerd Hoffmann 
1610f1ae32a1SGerd Hoffmann         /* PXA27x specific registers */
1611f1ae32a1SGerd Hoffmann         case 24: /* HcStatus */
1612f1ae32a1SGerd Hoffmann             retval = ohci->hstatus & ohci->hmask;
1613f1ae32a1SGerd Hoffmann             break;
1614f1ae32a1SGerd Hoffmann 
1615f1ae32a1SGerd Hoffmann         case 25: /* HcHReset */
1616f1ae32a1SGerd Hoffmann             retval = ohci->hreset;
1617f1ae32a1SGerd Hoffmann             break;
1618f1ae32a1SGerd Hoffmann 
1619f1ae32a1SGerd Hoffmann         case 26: /* HcHInterruptEnable */
1620f1ae32a1SGerd Hoffmann             retval = ohci->hmask;
1621f1ae32a1SGerd Hoffmann             break;
1622f1ae32a1SGerd Hoffmann 
1623f1ae32a1SGerd Hoffmann         case 27: /* HcHInterruptTest */
1624f1ae32a1SGerd Hoffmann             retval = ohci->htest;
1625f1ae32a1SGerd Hoffmann             break;
1626f1ae32a1SGerd Hoffmann 
1627f1ae32a1SGerd Hoffmann         default:
1628dc1f5988SAlexey Kardashevskiy             trace_usb_ohci_mem_read_bad_offset(addr);
1629f1ae32a1SGerd Hoffmann             retval = 0xffffffff;
1630f1ae32a1SGerd Hoffmann         }
1631f1ae32a1SGerd Hoffmann     }
1632f1ae32a1SGerd Hoffmann 
1633f1ae32a1SGerd Hoffmann     return retval;
1634f1ae32a1SGerd Hoffmann }
1635f1ae32a1SGerd Hoffmann 
1636f1ae32a1SGerd Hoffmann static void ohci_mem_write(void *opaque,
1637a8170e5eSAvi Kivity                            hwaddr addr,
1638f1ae32a1SGerd Hoffmann                            uint64_t val,
1639f1ae32a1SGerd Hoffmann                            unsigned size)
1640f1ae32a1SGerd Hoffmann {
1641f1ae32a1SGerd Hoffmann     OHCIState *ohci = opaque;
1642f1ae32a1SGerd Hoffmann 
1643f1ae32a1SGerd Hoffmann     /* Only aligned reads are allowed on OHCI */
1644f1ae32a1SGerd Hoffmann     if (addr & 3) {
1645dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_mem_write_unaligned(addr);
1646f1ae32a1SGerd Hoffmann         return;
1647f1ae32a1SGerd Hoffmann     }
1648f1ae32a1SGerd Hoffmann 
1649f1ae32a1SGerd Hoffmann     if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
1650f1ae32a1SGerd Hoffmann         /* HcRhPortStatus */
1651f1ae32a1SGerd Hoffmann         ohci_port_set_status(ohci, (addr - 0x54) >> 2, val);
1652f1ae32a1SGerd Hoffmann         return;
1653f1ae32a1SGerd Hoffmann     }
1654f1ae32a1SGerd Hoffmann 
1655f1ae32a1SGerd Hoffmann     switch (addr >> 2) {
1656f1ae32a1SGerd Hoffmann     case 1: /* HcControl */
1657f1ae32a1SGerd Hoffmann         ohci_set_ctl(ohci, val);
1658f1ae32a1SGerd Hoffmann         break;
1659f1ae32a1SGerd Hoffmann 
1660f1ae32a1SGerd Hoffmann     case 2: /* HcCommandStatus */
1661f1ae32a1SGerd Hoffmann         /* SOC is read-only */
1662f1ae32a1SGerd Hoffmann         val = (val & ~OHCI_STATUS_SOC);
1663f1ae32a1SGerd Hoffmann 
1664f1ae32a1SGerd Hoffmann         /* Bits written as '0' remain unchanged in the register */
1665f1ae32a1SGerd Hoffmann         ohci->status |= val;
1666f1ae32a1SGerd Hoffmann 
1667f1ae32a1SGerd Hoffmann         if (ohci->status & OHCI_STATUS_HCR)
16680922c3f6SHervé Poussineau             ohci_soft_reset(ohci);
1669f1ae32a1SGerd Hoffmann         break;
1670f1ae32a1SGerd Hoffmann 
1671f1ae32a1SGerd Hoffmann     case 3: /* HcInterruptStatus */
1672f1ae32a1SGerd Hoffmann         ohci->intr_status &= ~val;
1673f1ae32a1SGerd Hoffmann         ohci_intr_update(ohci);
1674f1ae32a1SGerd Hoffmann         break;
1675f1ae32a1SGerd Hoffmann 
1676f1ae32a1SGerd Hoffmann     case 4: /* HcInterruptEnable */
1677f1ae32a1SGerd Hoffmann         ohci->intr |= val;
1678f1ae32a1SGerd Hoffmann         ohci_intr_update(ohci);
1679f1ae32a1SGerd Hoffmann         break;
1680f1ae32a1SGerd Hoffmann 
1681f1ae32a1SGerd Hoffmann     case 5: /* HcInterruptDisable */
1682f1ae32a1SGerd Hoffmann         ohci->intr &= ~val;
1683f1ae32a1SGerd Hoffmann         ohci_intr_update(ohci);
1684f1ae32a1SGerd Hoffmann         break;
1685f1ae32a1SGerd Hoffmann 
1686f1ae32a1SGerd Hoffmann     case 6: /* HcHCCA */
1687f1ae32a1SGerd Hoffmann         ohci->hcca = val & OHCI_HCCA_MASK;
1688f1ae32a1SGerd Hoffmann         break;
1689f1ae32a1SGerd Hoffmann 
1690f1ae32a1SGerd Hoffmann     case 7: /* HcPeriodCurrentED */
1691f1ae32a1SGerd Hoffmann         /* Ignore writes to this read-only register, Linux does them */
1692f1ae32a1SGerd Hoffmann         break;
1693f1ae32a1SGerd Hoffmann 
1694f1ae32a1SGerd Hoffmann     case 8: /* HcControlHeadED */
1695f1ae32a1SGerd Hoffmann         ohci->ctrl_head = val & OHCI_EDPTR_MASK;
1696f1ae32a1SGerd Hoffmann         break;
1697f1ae32a1SGerd Hoffmann 
1698f1ae32a1SGerd Hoffmann     case 9: /* HcControlCurrentED */
1699f1ae32a1SGerd Hoffmann         ohci->ctrl_cur = val & OHCI_EDPTR_MASK;
1700f1ae32a1SGerd Hoffmann         break;
1701f1ae32a1SGerd Hoffmann 
1702f1ae32a1SGerd Hoffmann     case 10: /* HcBulkHeadED */
1703f1ae32a1SGerd Hoffmann         ohci->bulk_head = val & OHCI_EDPTR_MASK;
1704f1ae32a1SGerd Hoffmann         break;
1705f1ae32a1SGerd Hoffmann 
1706f1ae32a1SGerd Hoffmann     case 11: /* HcBulkCurrentED */
1707f1ae32a1SGerd Hoffmann         ohci->bulk_cur = val & OHCI_EDPTR_MASK;
1708f1ae32a1SGerd Hoffmann         break;
1709f1ae32a1SGerd Hoffmann 
1710f1ae32a1SGerd Hoffmann     case 13: /* HcFmInterval */
1711f1ae32a1SGerd Hoffmann         ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16;
1712f1ae32a1SGerd Hoffmann         ohci->fit = (val & OHCI_FMI_FIT) >> 31;
1713f1ae32a1SGerd Hoffmann         ohci_set_frame_interval(ohci, val);
1714f1ae32a1SGerd Hoffmann         break;
1715f1ae32a1SGerd Hoffmann 
1716f1ae32a1SGerd Hoffmann     case 15: /* HcFmNumber */
1717f1ae32a1SGerd Hoffmann         break;
1718f1ae32a1SGerd Hoffmann 
1719f1ae32a1SGerd Hoffmann     case 16: /* HcPeriodicStart */
1720f1ae32a1SGerd Hoffmann         ohci->pstart = val & 0xffff;
1721f1ae32a1SGerd Hoffmann         break;
1722f1ae32a1SGerd Hoffmann 
1723f1ae32a1SGerd Hoffmann     case 17: /* HcLSThreshold */
1724f1ae32a1SGerd Hoffmann         ohci->lst = val & 0xffff;
1725f1ae32a1SGerd Hoffmann         break;
1726f1ae32a1SGerd Hoffmann 
1727f1ae32a1SGerd Hoffmann     case 18: /* HcRhDescriptorA */
1728f1ae32a1SGerd Hoffmann         ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK;
1729f1ae32a1SGerd Hoffmann         ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK;
1730f1ae32a1SGerd Hoffmann         break;
1731f1ae32a1SGerd Hoffmann 
1732f1ae32a1SGerd Hoffmann     case 19: /* HcRhDescriptorB */
1733f1ae32a1SGerd Hoffmann         break;
1734f1ae32a1SGerd Hoffmann 
1735f1ae32a1SGerd Hoffmann     case 20: /* HcRhStatus */
1736f1ae32a1SGerd Hoffmann         ohci_set_hub_status(ohci, val);
1737f1ae32a1SGerd Hoffmann         break;
1738f1ae32a1SGerd Hoffmann 
1739f1ae32a1SGerd Hoffmann     /* PXA27x specific registers */
1740f1ae32a1SGerd Hoffmann     case 24: /* HcStatus */
1741f1ae32a1SGerd Hoffmann         ohci->hstatus &= ~(val & ohci->hmask);
17427fa96d73SGerd Hoffmann         break;
1743f1ae32a1SGerd Hoffmann 
1744f1ae32a1SGerd Hoffmann     case 25: /* HcHReset */
1745f1ae32a1SGerd Hoffmann         ohci->hreset = val & ~OHCI_HRESET_FSBIR;
1746f1ae32a1SGerd Hoffmann         if (val & OHCI_HRESET_FSBIR)
174784d04e21SHervé Poussineau             ohci_hard_reset(ohci);
1748f1ae32a1SGerd Hoffmann         break;
1749f1ae32a1SGerd Hoffmann 
1750f1ae32a1SGerd Hoffmann     case 26: /* HcHInterruptEnable */
1751f1ae32a1SGerd Hoffmann         ohci->hmask = val;
1752f1ae32a1SGerd Hoffmann         break;
1753f1ae32a1SGerd Hoffmann 
1754f1ae32a1SGerd Hoffmann     case 27: /* HcHInterruptTest */
1755f1ae32a1SGerd Hoffmann         ohci->htest = val;
1756f1ae32a1SGerd Hoffmann         break;
1757f1ae32a1SGerd Hoffmann 
1758f1ae32a1SGerd Hoffmann     default:
1759dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_mem_write_bad_offset(addr);
1760f1ae32a1SGerd Hoffmann         break;
1761f1ae32a1SGerd Hoffmann     }
1762f1ae32a1SGerd Hoffmann }
1763f1ae32a1SGerd Hoffmann 
1764f1ae32a1SGerd Hoffmann static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
1765f1ae32a1SGerd Hoffmann {
1766f1ae32a1SGerd Hoffmann     if (ohci->async_td &&
1767f1ae32a1SGerd Hoffmann         usb_packet_is_inflight(&ohci->usb_packet) &&
1768f1ae32a1SGerd Hoffmann         ohci->usb_packet.ep->dev == dev) {
1769f1ae32a1SGerd Hoffmann         usb_cancel_packet(&ohci->usb_packet);
1770f1ae32a1SGerd Hoffmann         ohci->async_td = 0;
1771f1ae32a1SGerd Hoffmann     }
1772f1ae32a1SGerd Hoffmann }
1773f1ae32a1SGerd Hoffmann 
1774f1ae32a1SGerd Hoffmann static const MemoryRegionOps ohci_mem_ops = {
1775f1ae32a1SGerd Hoffmann     .read = ohci_mem_read,
1776f1ae32a1SGerd Hoffmann     .write = ohci_mem_write,
1777f1ae32a1SGerd Hoffmann     .endianness = DEVICE_LITTLE_ENDIAN,
1778f1ae32a1SGerd Hoffmann };
1779f1ae32a1SGerd Hoffmann 
1780f1ae32a1SGerd Hoffmann static USBPortOps ohci_port_ops = {
1781f1ae32a1SGerd Hoffmann     .attach = ohci_attach,
1782f1ae32a1SGerd Hoffmann     .detach = ohci_detach,
1783f1ae32a1SGerd Hoffmann     .child_detach = ohci_child_detach,
1784f1ae32a1SGerd Hoffmann     .wakeup = ohci_wakeup,
1785f1ae32a1SGerd Hoffmann     .complete = ohci_async_complete_packet,
1786f1ae32a1SGerd Hoffmann };
1787f1ae32a1SGerd Hoffmann 
1788f1ae32a1SGerd Hoffmann static USBBusOps ohci_bus_ops = {
1789f1ae32a1SGerd Hoffmann };
1790f1ae32a1SGerd Hoffmann 
179134d97308SThomas Huth void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports,
179234d97308SThomas Huth                    dma_addr_t localmem_base, char *masterbus,
179334d97308SThomas Huth                    uint32_t firstport, AddressSpace *as,
179472e0c127SThomas Huth                    void (*ohci_die_fn)(struct OHCIState *), Error **errp)
1795f1ae32a1SGerd Hoffmann {
1796f4bbaaf5SMarkus Armbruster     Error *err = NULL;
1797f1ae32a1SGerd Hoffmann     int i;
1798f1ae32a1SGerd Hoffmann 
1799df32fd1cSPaolo Bonzini     ohci->as = as;
180072e0c127SThomas Huth     ohci->ohci_die = ohci_die_fn;
18019ac6a217SDavid Gibson 
1802d400fc01SThomas Huth     if (num_ports > OHCI_MAX_PORTS) {
1803b9a3a4f2SLi Qiang         error_setg(errp, "OHCI num-ports=%u is too big (limit is %u ports)",
1804d400fc01SThomas Huth                    num_ports, OHCI_MAX_PORTS);
1805d400fc01SThomas Huth         return;
1806d400fc01SThomas Huth     }
1807d400fc01SThomas Huth 
1808f1ae32a1SGerd Hoffmann     if (usb_frame_time == 0) {
1809f1ae32a1SGerd Hoffmann #ifdef OHCI_TIME_WARP
181073bcb24dSRutuja Shah         usb_frame_time = NANOSECONDS_PER_SECOND;
181173bcb24dSRutuja Shah         usb_bit_time = NANOSECONDS_PER_SECOND / (USB_HZ / 1000);
1812f1ae32a1SGerd Hoffmann #else
181373bcb24dSRutuja Shah         usb_frame_time = NANOSECONDS_PER_SECOND / 1000;
181473bcb24dSRutuja Shah         if (NANOSECONDS_PER_SECOND >= USB_HZ) {
181573bcb24dSRutuja Shah             usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ;
1816f1ae32a1SGerd Hoffmann         } else {
1817f1ae32a1SGerd Hoffmann             usb_bit_time = 1;
1818f1ae32a1SGerd Hoffmann         }
1819f1ae32a1SGerd Hoffmann #endif
1820dc1f5988SAlexey Kardashevskiy         trace_usb_ohci_init_time(usb_frame_time, usb_bit_time);
1821f1ae32a1SGerd Hoffmann     }
1822f1ae32a1SGerd Hoffmann 
1823f1ae32a1SGerd Hoffmann     ohci->num_ports = num_ports;
1824f1ae32a1SGerd Hoffmann     if (masterbus) {
1825f1ae32a1SGerd Hoffmann         USBPort *ports[OHCI_MAX_PORTS];
1826f1ae32a1SGerd Hoffmann         for(i = 0; i < num_ports; i++) {
1827f1ae32a1SGerd Hoffmann             ports[i] = &ohci->rhport[i].port;
1828f1ae32a1SGerd Hoffmann         }
1829f4bbaaf5SMarkus Armbruster         usb_register_companion(masterbus, ports, num_ports,
1830f1ae32a1SGerd Hoffmann                                firstport, ohci, &ohci_port_ops,
1831f4bbaaf5SMarkus Armbruster                                USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL,
1832f4bbaaf5SMarkus Armbruster                                &err);
1833f4bbaaf5SMarkus Armbruster         if (err) {
183487581feaSMarkus Armbruster             error_propagate(errp, err);
183587581feaSMarkus Armbruster             return;
1836f1ae32a1SGerd Hoffmann         }
1837f1ae32a1SGerd Hoffmann     } else {
1838c889b3a5SAndreas Färber         usb_bus_new(&ohci->bus, sizeof(ohci->bus), &ohci_bus_ops, dev);
1839f1ae32a1SGerd Hoffmann         for (i = 0; i < num_ports; i++) {
1840f1ae32a1SGerd Hoffmann             usb_register_port(&ohci->bus, &ohci->rhport[i].port,
1841f1ae32a1SGerd Hoffmann                               ohci, i, &ohci_port_ops,
1842f1ae32a1SGerd Hoffmann                               USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
1843f1ae32a1SGerd Hoffmann         }
1844f1ae32a1SGerd Hoffmann     }
1845f1ae32a1SGerd Hoffmann 
184622fc860bSPaolo Bonzini     memory_region_init_io(&ohci->mem, OBJECT(dev), &ohci_mem_ops,
184722fc860bSPaolo Bonzini                           ohci, "ohci", 256);
1848f1ae32a1SGerd Hoffmann     ohci->localmem_base = localmem_base;
1849f1ae32a1SGerd Hoffmann 
1850f1ae32a1SGerd Hoffmann     ohci->name = object_get_typename(OBJECT(dev));
1851f1ae32a1SGerd Hoffmann     usb_packet_init(&ohci->usb_packet);
1852f1ae32a1SGerd Hoffmann 
1853f1ae32a1SGerd Hoffmann     ohci->async_td = 0;
1854fa1298c2SGerd Hoffmann 
1855fa1298c2SGerd Hoffmann     ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
1856fa1298c2SGerd Hoffmann                                    ohci_frame_boundary, ohci);
1857f1ae32a1SGerd Hoffmann }
1858f1ae32a1SGerd Hoffmann 
185972e0c127SThomas Huth /**
186072e0c127SThomas Huth  * A typical OHCI will stop operating and set itself into error state
186172e0c127SThomas Huth  * (which can be queried by MMIO) to signal that it got an error.
1862cf66ee8eSAlexey Kardashevskiy  */
186334d97308SThomas Huth void ohci_sysbus_die(struct OHCIState *ohci)
1864cf66ee8eSAlexey Kardashevskiy {
1865dc1f5988SAlexey Kardashevskiy     trace_usb_ohci_die();
1866cf66ee8eSAlexey Kardashevskiy 
1867cf66ee8eSAlexey Kardashevskiy     ohci_set_interrupt(ohci, OHCI_INTR_UE);
1868cf66ee8eSAlexey Kardashevskiy     ohci_bus_stop(ohci);
186972e0c127SThomas Huth }
187072e0c127SThomas Huth 
18711aa0c0c7SHu Tao #define TYPE_SYSBUS_OHCI "sysbus-ohci"
18721aa0c0c7SHu Tao #define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI)
18731aa0c0c7SHu Tao 
1874f1ae32a1SGerd Hoffmann typedef struct {
18751aa0c0c7SHu Tao     /*< private >*/
18761aa0c0c7SHu Tao     SysBusDevice parent_obj;
18771aa0c0c7SHu Tao     /*< public >*/
18781aa0c0c7SHu Tao 
1879f1ae32a1SGerd Hoffmann     OHCIState ohci;
1880d7145b66SBALATON Zoltan     char *masterbus;
1881f1ae32a1SGerd Hoffmann     uint32_t num_ports;
1882d7145b66SBALATON Zoltan     uint32_t firstport;
18839ac6a217SDavid Gibson     dma_addr_t dma_offset;
1884f1ae32a1SGerd Hoffmann } OHCISysBusState;
1885f1ae32a1SGerd Hoffmann 
1886457215ecSHu Tao static void ohci_realize_pxa(DeviceState *dev, Error **errp)
1887f1ae32a1SGerd Hoffmann {
18881aa0c0c7SHu Tao     OHCISysBusState *s = SYSBUS_OHCI(dev);
1889457215ecSHu Tao     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
1890d7145b66SBALATON Zoltan     Error *err = NULL;
1891f1ae32a1SGerd Hoffmann 
1892d7145b66SBALATON Zoltan     usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset,
1893d7145b66SBALATON Zoltan                   s->masterbus, s->firstport,
189472e0c127SThomas Huth                   &address_space_memory, ohci_sysbus_die, &err);
1895d7145b66SBALATON Zoltan     if (err) {
1896d7145b66SBALATON Zoltan         error_propagate(errp, err);
1897d7145b66SBALATON Zoltan         return;
1898d7145b66SBALATON Zoltan     }
1899457215ecSHu Tao     sysbus_init_irq(sbd, &s->ohci.irq);
1900457215ecSHu Tao     sysbus_init_mmio(sbd, &s->ohci.mem);
1901f1ae32a1SGerd Hoffmann }
1902f1ae32a1SGerd Hoffmann 
190388dd1b8dSGonglei static void usb_ohci_reset_sysbus(DeviceState *dev)
190488dd1b8dSGonglei {
190588dd1b8dSGonglei     OHCISysBusState *s = SYSBUS_OHCI(dev);
190688dd1b8dSGonglei     OHCIState *ohci = &s->ohci;
190788dd1b8dSGonglei 
190884d04e21SHervé Poussineau     ohci_hard_reset(ohci);
190988dd1b8dSGonglei }
191088dd1b8dSGonglei 
191169e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci_state_port = {
191269e25d26SAlexey Kardashevskiy     .name = "ohci-core/port",
191369e25d26SAlexey Kardashevskiy     .version_id = 1,
191469e25d26SAlexey Kardashevskiy     .minimum_version_id = 1,
191569e25d26SAlexey Kardashevskiy     .fields = (VMStateField[]) {
191669e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(ctrl, OHCIPort),
191769e25d26SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
191869e25d26SAlexey Kardashevskiy     },
191969e25d26SAlexey Kardashevskiy };
192069e25d26SAlexey Kardashevskiy 
192169e25d26SAlexey Kardashevskiy static bool ohci_eof_timer_needed(void *opaque)
192269e25d26SAlexey Kardashevskiy {
192369e25d26SAlexey Kardashevskiy     OHCIState *ohci = opaque;
192469e25d26SAlexey Kardashevskiy 
1925fa1298c2SGerd Hoffmann     return timer_pending(ohci->eof_timer);
192669e25d26SAlexey Kardashevskiy }
192769e25d26SAlexey Kardashevskiy 
192869e25d26SAlexey Kardashevskiy static const VMStateDescription vmstate_ohci_eof_timer = {
192969e25d26SAlexey Kardashevskiy     .name = "ohci-core/eof-timer",
193069e25d26SAlexey Kardashevskiy     .version_id = 1,
193169e25d26SAlexey Kardashevskiy     .minimum_version_id = 1,
19325cd8cadaSJuan Quintela     .needed = ohci_eof_timer_needed,
193369e25d26SAlexey Kardashevskiy     .fields = (VMStateField[]) {
1934e720677eSPaolo Bonzini         VMSTATE_TIMER_PTR(eof_timer, OHCIState),
193569e25d26SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
193669e25d26SAlexey Kardashevskiy     },
193769e25d26SAlexey Kardashevskiy };
193869e25d26SAlexey Kardashevskiy 
193934d97308SThomas Huth const VMStateDescription vmstate_ohci_state = {
194069e25d26SAlexey Kardashevskiy     .name = "ohci-core",
194169e25d26SAlexey Kardashevskiy     .version_id = 1,
194269e25d26SAlexey Kardashevskiy     .minimum_version_id = 1,
194369e25d26SAlexey Kardashevskiy     .fields = (VMStateField[]) {
194469e25d26SAlexey Kardashevskiy         VMSTATE_INT64(sof_time, OHCIState),
194569e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(ctl, OHCIState),
194669e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(status, OHCIState),
194769e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(intr_status, OHCIState),
194869e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(intr, OHCIState),
194969e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(hcca, OHCIState),
195069e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(ctrl_head, OHCIState),
195169e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(ctrl_cur, OHCIState),
195269e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(bulk_head, OHCIState),
195369e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(bulk_cur, OHCIState),
195469e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(per_cur, OHCIState),
195569e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(done, OHCIState),
195669e25d26SAlexey Kardashevskiy         VMSTATE_INT32(done_count, OHCIState),
195769e25d26SAlexey Kardashevskiy         VMSTATE_UINT16(fsmps, OHCIState),
195869e25d26SAlexey Kardashevskiy         VMSTATE_UINT8(fit, OHCIState),
195969e25d26SAlexey Kardashevskiy         VMSTATE_UINT16(fi, OHCIState),
196069e25d26SAlexey Kardashevskiy         VMSTATE_UINT8(frt, OHCIState),
196169e25d26SAlexey Kardashevskiy         VMSTATE_UINT16(frame_number, OHCIState),
196269e25d26SAlexey Kardashevskiy         VMSTATE_UINT16(padding, OHCIState),
196369e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(pstart, OHCIState),
196469e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(lst, OHCIState),
196569e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(rhdesc_a, OHCIState),
196669e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(rhdesc_b, OHCIState),
196769e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(rhstatus, OHCIState),
196869e25d26SAlexey Kardashevskiy         VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0,
196969e25d26SAlexey Kardashevskiy                              vmstate_ohci_state_port, OHCIPort),
197069e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(hstatus, OHCIState),
197169e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(hmask, OHCIState),
197269e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(hreset, OHCIState),
197369e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(htest, OHCIState),
197469e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(old_ctl, OHCIState),
197569e25d26SAlexey Kardashevskiy         VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192),
197669e25d26SAlexey Kardashevskiy         VMSTATE_UINT32(async_td, OHCIState),
197769e25d26SAlexey Kardashevskiy         VMSTATE_BOOL(async_complete, OHCIState),
197869e25d26SAlexey Kardashevskiy         VMSTATE_END_OF_LIST()
197969e25d26SAlexey Kardashevskiy     },
19805cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
19815cd8cadaSJuan Quintela         &vmstate_ohci_eof_timer,
19825cd8cadaSJuan Quintela         NULL
198369e25d26SAlexey Kardashevskiy     }
198469e25d26SAlexey Kardashevskiy };
198569e25d26SAlexey Kardashevskiy 
1986f1ae32a1SGerd Hoffmann static Property ohci_sysbus_properties[] = {
1987d7145b66SBALATON Zoltan     DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus),
1988f1ae32a1SGerd Hoffmann     DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
1989d7145b66SBALATON Zoltan     DEFINE_PROP_UINT32("firstport", OHCISysBusState, firstport, 0),
19906998b6c7SVijay Kumar B     DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 0),
1991f1ae32a1SGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
1992f1ae32a1SGerd Hoffmann };
1993f1ae32a1SGerd Hoffmann 
1994f1ae32a1SGerd Hoffmann static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
1995f1ae32a1SGerd Hoffmann {
1996f1ae32a1SGerd Hoffmann     DeviceClass *dc = DEVICE_CLASS(klass);
1997f1ae32a1SGerd Hoffmann 
1998457215ecSHu Tao     dc->realize = ohci_realize_pxa;
1999125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_USB, dc->categories);
2000f1ae32a1SGerd Hoffmann     dc->desc = "OHCI USB Controller";
2001f1ae32a1SGerd Hoffmann     dc->props = ohci_sysbus_properties;
200288dd1b8dSGonglei     dc->reset = usb_ohci_reset_sysbus;
2003f1ae32a1SGerd Hoffmann }
2004f1ae32a1SGerd Hoffmann 
20058c43a6f0SAndreas Färber static const TypeInfo ohci_sysbus_info = {
20061aa0c0c7SHu Tao     .name          = TYPE_SYSBUS_OHCI,
2007f1ae32a1SGerd Hoffmann     .parent        = TYPE_SYS_BUS_DEVICE,
2008f1ae32a1SGerd Hoffmann     .instance_size = sizeof(OHCISysBusState),
2009f1ae32a1SGerd Hoffmann     .class_init    = ohci_sysbus_class_init,
2010f1ae32a1SGerd Hoffmann };
2011f1ae32a1SGerd Hoffmann 
2012f1ae32a1SGerd Hoffmann static void ohci_register_types(void)
2013f1ae32a1SGerd Hoffmann {
2014f1ae32a1SGerd Hoffmann     type_register_static(&ohci_sysbus_info);
2015f1ae32a1SGerd Hoffmann }
2016f1ae32a1SGerd Hoffmann 
2017f1ae32a1SGerd Hoffmann type_init(ohci_register_types)
2018