18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * QEMU USB OHCI Emulation
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2004 Gianni Tedesco
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2006 CodeSourcery
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2006 Openedhand Ltd.
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * This library is free software; you can redistribute it and/or
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * modify it under the terms of the GNU Lesser General Public
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * License as published by the Free Software Foundation; either
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * version 2 of the License, or (at your option) any later version.
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * This library is distributed in the hope that it will be useful,
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * but WITHOUT ANY WARRANTY; without even the implied warranty of
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Lesser General Public License for more details.
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * You should have received a copy of the GNU Lesser General Public
18a7fb77d6eca56e61e94f62e7deb4120b60b1e919David 'Digit' Turner * License along with this library; if not, see <http://www.gnu.org/licenses/>.
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * TODO:
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *  o Isochronous transfers
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *  o Allocate bandwidth in frames properly
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *  o Disable timers when nothing needs to be done, or remove timer usage
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *    all together.
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *  o Handle unrecoverable errors properly
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *  o BIOS work to boot from USB storage
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project*/
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "hw.h"
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-timer.h"
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "usb.h"
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "pci.h"
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "pxa.h"
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "devices.h"
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//#define DEBUG_OHCI
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Dump packet contents.  */
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//#define DEBUG_PACKET
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//#define DEBUG_ISOCH
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* This causes frames to occur 1000x slower */
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//#define OHCI_TIME_WARP 1
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_OHCI
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define dprintf printf
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define dprintf(...)
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Number of Downstream Ports on the root hub.  */
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_MAX_PORTS 15
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int64_t usb_frame_time;
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int64_t usb_bit_time;
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct OHCIPort {
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    USBPort port;
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t ctrl;
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} OHCIPort;
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectenum ohci_type {
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCI_TYPE_PCI,
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    OHCI_TYPE_PXA,
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    OHCI_TYPE_SM501,
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct {
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_irq irq;
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    enum ohci_type type;
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int mem;
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int num_ports;
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char *name;
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    QEMUTimer *eof_timer;
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int64_t sof_time;
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* OHCI state */
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Control partition */
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t ctl, status;
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t intr_status;
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t intr;
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* memory pointer partition */
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t hcca;
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t ctrl_head, ctrl_cur;
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t bulk_head, bulk_cur;
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t per_cur;
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t done;
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int done_count;
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Frame counter partition */
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t fsmps:15;
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t fit:1;
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t fi:14;
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t frt:1;
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t frame_number;
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t padding;
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t pstart;
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t lst;
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Root Hub partition */
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t rhdesc_a, rhdesc_b;
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t rhstatus;
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIPort rhport[OHCI_MAX_PORTS];
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* PXA27x Non-OHCI events */
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t hstatus;
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t hmask;
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t hreset;
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t htest;
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* SM501 local memory offset */
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    target_phys_addr_t localmem_base;
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Active packets.  */
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t old_ctl;
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    USBPacket usb_packet;
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t usb_buf[8192];
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t async_td;
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int async_complete;
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} OHCIState;
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Host Controller Communications Area */
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct ohci_hcca {
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t intr[32];
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t frame, pad;
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t done;
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_bus_stop(OHCIState *ohci);
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Bitfields for the first word of an Endpoint Desciptor.  */
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_FA_SHIFT  0
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_FA_MASK   (0x7f<<OHCI_ED_FA_SHIFT)
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_EN_SHIFT  7
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_EN_MASK   (0xf<<OHCI_ED_EN_SHIFT)
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_D_SHIFT   11
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_D_MASK    (3<<OHCI_ED_D_SHIFT)
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_S         (1<<13)
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_K         (1<<14)
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_F         (1<<15)
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_MPS_SHIFT 16
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_MPS_MASK  (0x7ff<<OHCI_ED_MPS_SHIFT)
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Flags in the head field of an Endpoint Desciptor.  */
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_H         1
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_ED_C         2
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Bitfields for the first word of a Transfer Desciptor.  */
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_R         (1<<18)
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_DP_SHIFT  19
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_DP_MASK   (3<<OHCI_TD_DP_SHIFT)
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_DI_SHIFT  21
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_DI_MASK   (7<<OHCI_TD_DI_SHIFT)
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_T0        (1<<24)
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_T1        (1<<24)
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_EC_SHIFT  26
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_EC_MASK   (3<<OHCI_TD_EC_SHIFT)
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_CC_SHIFT  28
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_CC_MASK   (0xf<<OHCI_TD_CC_SHIFT)
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Bitfields for the first word of an Isochronous Transfer Desciptor.  */
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* CC & DI - same as in the General Transfer Desciptor */
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_SF_SHIFT  0
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_SF_MASK   (0xffff<<OHCI_TD_SF_SHIFT)
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_FC_SHIFT  24
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_FC_MASK   (7<<OHCI_TD_FC_SHIFT)
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Isochronous Transfer Desciptor - Offset / PacketStatusWord */
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_PSW_CC_SHIFT 12
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_PSW_CC_MASK  (0xf<<OHCI_TD_PSW_CC_SHIFT)
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_PSW_SIZE_SHIFT 0
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_PSW_SIZE_MASK  (0xfff<<OHCI_TD_PSW_SIZE_SHIFT)
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PAGE_MASK    0xfffff000
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_OFFSET_MASK  0xfff
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_DPTR_MASK    0xfffffff0
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_BM(val, field) \
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project  (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT)
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_SET_BM(val, field, newval) do { \
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    val &= ~OHCI_##field##_MASK; \
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } while(0)
1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* endpoint descriptor */
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct ohci_ed {
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t flags;
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t tail;
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t head;
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t next;
1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* General transfer descriptor */
1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct ohci_td {
1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t flags;
2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t cbp;
2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t next;
2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t be;
2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Isochronous transfer descriptor */
2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct ohci_iso_td {
2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t flags;
2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t bp;
2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t next;
2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t be;
2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t offset[8];
2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define USB_HZ                      12000000
2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* OHCI Local stuff */
2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CTL_CBSR         ((1<<0)|(1<<1))
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CTL_PLE          (1<<2)
2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CTL_IE           (1<<3)
2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CTL_CLE          (1<<4)
2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CTL_BLE          (1<<5)
2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CTL_HCFS         ((1<<6)|(1<<7))
2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  OHCI_USB_RESET       0x00
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  OHCI_USB_RESUME      0x40
2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  OHCI_USB_OPERATIONAL 0x80
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  OHCI_USB_SUSPEND     0xc0
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CTL_IR           (1<<8)
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CTL_RWC          (1<<9)
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CTL_RWE          (1<<10)
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_STATUS_HCR       (1<<0)
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_STATUS_CLF       (1<<1)
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_STATUS_BLF       (1<<2)
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_STATUS_OCR       (1<<3)
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_STATUS_SOC       ((1<<6)|(1<<7))
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_INTR_SO          (1<<0) /* Scheduling overrun */
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_INTR_WD          (1<<1) /* HcDoneHead writeback */
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_INTR_SF          (1<<2) /* Start of frame */
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_INTR_RD          (1<<3) /* Resume detect */
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_INTR_UE          (1<<4) /* Unrecoverable error */
2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_INTR_FNO         (1<<5) /* Frame number overflow */
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_INTR_RHSC        (1<<6) /* Root hub status change */
2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_INTR_OC          (1<<30) /* Ownership change */
2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_INTR_MIE         (1<<31) /* Master Interrupt Enable */
2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_HCCA_SIZE        0x100
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_HCCA_MASK        0xffffff00
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_EDPTR_MASK       0xfffffff0
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_FMI_FI           0x00003fff
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_FMI_FSMPS        0xffff0000
2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_FMI_FIT          0x80000000
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_FR_RT            (1<<31)
2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_LS_THRESH        0x628
2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHA_RW_MASK      0x00000000 /* Mask of supported features.  */
2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHA_PSM          (1<<8)
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHA_NPS          (1<<9)
2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHA_DT           (1<<10)
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHA_OCPM         (1<<11)
2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHA_NOCP         (1<<12)
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHA_POTPGT_MASK  0xff000000
2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHS_LPS          (1<<0)
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHS_OCI          (1<<1)
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHS_DRWE         (1<<15)
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHS_LPSC         (1<<16)
2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHS_OCIC         (1<<17)
2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_RHS_CRWE         (1<<31)
2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_CCS         (1<<0)
2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_PES         (1<<1)
2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_PSS         (1<<2)
2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_POCI        (1<<3)
2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_PRS         (1<<4)
2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_PPS         (1<<8)
2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_LSDA        (1<<9)
2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_CSC         (1<<16)
2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_PESC        (1<<17)
2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_PSSC        (1<<18)
2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_OCIC        (1<<19)
2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_PRSC        (1<<20)
2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_PORT_WTC         (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \
2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                               |OHCI_PORT_OCIC|OHCI_PORT_PRSC)
2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_DIR_SETUP     0x0
2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_DIR_OUT       0x1
2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_DIR_IN        0x2
2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_TD_DIR_RESERVED  0x3
2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_NOERROR             0x0
2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_CRC                 0x1
2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_BITSTUFFING         0x2
2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_DATATOGGLEMISMATCH  0x3
2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_STALL               0x4
3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_DEVICENOTRESPONDING 0x5
3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_PIDCHECKFAILURE     0x6
3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_UNDEXPETEDPID       0x7
3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_DATAOVERRUN         0x8
3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_DATAUNDERRUN        0x9
3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_BUFFEROVERRUN       0xc
3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_CC_BUFFERUNDERRUN      0xd
3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define OHCI_HRESET_FSBIR       (1 << 0)
3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Update IRQ levels */
3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void ohci_intr_update(OHCIState *ohci)
3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int level = 0;
3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((ohci->intr & OHCI_INTR_MIE) &&
3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        (ohci->intr_status & ohci->intr))
3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        level = 1;
3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_set_irq(ohci->irq, level);
3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Set an interrupt */
3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->intr_status |= intr;
3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_intr_update(ohci);
3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Attach or detach a device on a root hub port.  */
3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_attach(USBPort *port1, USBDevice *dev)
3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIState *s = port1->opaque;
3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIPort *port = &s->rhport[port1->index];
3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t old_state = port->ctrl;
3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (dev) {
3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (port->port.dev) {
3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            usb_attach(port1, NULL);
3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* set connect status */
3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* update speed */
3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (dev->speed == USB_SPEED_LOW)
3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            port->ctrl |= OHCI_PORT_LSDA;
3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else
3478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            port->ctrl &= ~OHCI_PORT_LSDA;
3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        port->port.dev = dev;
3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* notify of remote-wakeup */
3518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND)
3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci_set_interrupt(s, OHCI_INTR_RD);
3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* send the attach message */
3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        usb_send_msg(dev, USB_MSG_ATTACH);
3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: Attached port %d\n", port1->index);
3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* set connect status */
3598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (port->ctrl & OHCI_PORT_CCS) {
3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            port->ctrl &= ~OHCI_PORT_CCS;
3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            port->ctrl |= OHCI_PORT_CSC;
3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* disable port */
3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (port->ctrl & OHCI_PORT_PES) {
3658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            port->ctrl &= ~OHCI_PORT_PES;
3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            port->ctrl |= OHCI_PORT_PESC;
3678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dev = port->port.dev;
3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (dev) {
3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* send the detach message */
3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            usb_send_msg(dev, USB_MSG_DETACH);
3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        port->port.dev = NULL;
3748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: Detached port %d\n", port1->index);
3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (old_state != port->ctrl)
3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_set_interrupt(s, OHCI_INTR_RHSC);
3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Reset the controller */
3828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_reset(void *opaque)
3838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIState *ohci = opaque;
3858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIPort *port;
3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_bus_stop(ohci);
3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->ctl = 0;
3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->old_ctl = 0;
3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->status = 0;
3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->intr_status = 0;
3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->intr = OHCI_INTR_MIE;
3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->hcca = 0;
3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->ctrl_head = ohci->ctrl_cur = 0;
3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->bulk_head = ohci->bulk_cur = 0;
3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->per_cur = 0;
3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->done = 0;
4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->done_count = 7;
4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* FSMPS is marked TBD in OCHI 1.0, what gives ffs?
4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * I took the value linux sets ...
4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->fsmps = 0x2778;
4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->fi = 0x2edf;
4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->fit = 0;
4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->frt = 0;
4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->frame_number = 0;
4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->pstart = 0;
4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->lst = OHCI_LS_THRESH;
4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports;
4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->rhdesc_b = 0x0; /* Impl. specific */
4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->rhstatus = 0;
4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < ohci->num_ports; i++)
4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project      {
4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        port = &ohci->rhport[i];
4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        port->ctrl = 0;
4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (port->port.dev)
4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci_attach(&port->port, port->port.dev);
4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project      }
4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci->async_td) {
4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        usb_cancel_packet(&ohci->usb_packet);
4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->async_td = 0;
4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dprintf("usb-ohci: Reset %s\n", ohci->name);
4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Get an array of dwords from main memory */
4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int get_dwords(OHCIState *ohci,
4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                             uint32_t addr, uint32_t *buf, int num)
4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr += ohci->localmem_base;
4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *buf = le32_to_cpu(*buf);
4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 1;
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Put an array of dwords in to main memory */
4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int put_dwords(OHCIState *ohci,
4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                             uint32_t addr, uint32_t *buf, int num)
4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr += ohci->localmem_base;
4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint32_t tmp = cpu_to_le32(*buf);
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 1;
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Get an array of words from main memory */
4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int get_words(OHCIState *ohci,
4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            uint32_t addr, uint16_t *buf, int num)
4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr += ohci->localmem_base;
4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *buf = le16_to_cpu(*buf);
4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 1;
4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Put an array of words in to main memory */
4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int put_words(OHCIState *ohci,
4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            uint32_t addr, uint16_t *buf, int num)
4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr += ohci->localmem_base;
4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint16_t tmp = cpu_to_le16(*buf);
4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 1;
4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int ohci_read_ed(OHCIState *ohci,
4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               uint32_t addr, struct ohci_ed *ed)
4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int ohci_read_td(OHCIState *ohci,
5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               uint32_t addr, struct ohci_td *td)
5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int ohci_read_iso_td(OHCIState *ohci,
5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   uint32_t addr, struct ohci_iso_td *td)
5098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return (get_dwords(ohci, addr, (uint32_t *)td, 4) &&
5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            get_words(ohci, addr + 16, td->offset, 8));
5128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int ohci_read_hcca(OHCIState *ohci,
5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 uint32_t addr, struct ohci_hcca *hcca)
5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cpu_physical_memory_rw(addr + ohci->localmem_base,
5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           (uint8_t *)hcca, sizeof(*hcca), 0);
5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 1;
5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int ohci_put_ed(OHCIState *ohci,
5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                              uint32_t addr, struct ohci_ed *ed)
5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return put_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int ohci_put_td(OHCIState *ohci,
5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                              uint32_t addr, struct ohci_td *td)
5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int ohci_put_iso_td(OHCIState *ohci,
5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                  uint32_t addr, struct ohci_iso_td *td)
5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return (put_dwords(ohci, addr, (uint32_t *)td, 4) &&
5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            put_words(ohci, addr + 16, td->offset, 8));
5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic inline int ohci_put_hcca(OHCIState *ohci,
5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                uint32_t addr, struct ohci_hcca *hcca)
5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cpu_physical_memory_rw(addr + ohci->localmem_base,
5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           (uint8_t *)hcca, sizeof(*hcca), 1);
5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 1;
5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Read/Write the contents of a TD from/to main memory.  */
5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void ohci_copy_td(OHCIState *ohci, struct ohci_td *td,
5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         uint8_t *buf, int len, int write)
5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t ptr;
5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t n;
5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ptr = td->cbp;
5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    n = 0x1000 - (ptr & 0xfff);
5588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (n > len)
5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        n = len;
5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, n, write);
5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (n == len)
5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ptr = td->be & ~0xfffu;
5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    buf += n;
5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, len - n, write);
5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Read/Write the contents of an ISO TD from/to main memory.  */
5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void ohci_copy_iso_td(OHCIState *ohci,
5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                             uint32_t start_addr, uint32_t end_addr,
5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                             uint8_t *buf, int len, int write)
5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t ptr;
5748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t n;
5758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ptr = start_addr;
5778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    n = 0x1000 - (ptr & 0xfff);
5788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (n > len)
5798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        n = len;
5805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, n, write);
5818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (n == len)
5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
5838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ptr = end_addr & ~0xfffu;
5848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    buf += n;
5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, len - n, write);
5868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_process_lists(OHCIState *ohci, int completion);
5898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_async_complete_packet(USBPacket *packet, void *opaque)
5918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIState *ohci = opaque;
5938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_PACKET
5948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dprintf("Async packet complete\n");
5958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
5968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->async_complete = 1;
5978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_process_lists(ohci, 1);
5988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b)))
6018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
6038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                               int completion)
6048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int dir;
6068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t len = 0;
6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char *str = NULL;
6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int pid;
6098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ret;
6108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
6118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    USBDevice *dev;
6128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct ohci_iso_td iso_td;
6138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t addr;
6148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t starting_frame;
6158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int16_t relative_frame_number;
6168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int frame_count;
6178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t start_offset, next_offset, end_offset = 0;
6188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t start_addr, end_addr;
6198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    addr = ed->head & OHCI_DPTR_MASK;
6218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!ohci_read_iso_td(ohci, addr, &iso_td)) {
6238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        printf("usb-ohci: ISO_TD read error at %x\n", addr);
6248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
6258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    starting_frame = OHCI_BM(iso_td.flags, TD_SF);
6288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    frame_count = OHCI_BM(iso_td.flags, TD_FC);
6295973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    relative_frame_number = USUB(ohci->frame_number, starting_frame);
6308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_ISOCH
6328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    printf("--- ISO_TD ED head 0x%.8x tailp 0x%.8x\n"
6338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
6348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
6358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
6368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           "frame_number 0x%.8x starting_frame 0x%.8x\n"
6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           "frame_count  0x%.8x relative %d\n"
6388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           "di 0x%.8x cc 0x%.8x\n",
6398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK,
6408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           iso_td.flags, iso_td.bp, iso_td.next, iso_td.be,
6418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           iso_td.offset[0], iso_td.offset[1], iso_td.offset[2], iso_td.offset[3],
6428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           iso_td.offset[4], iso_td.offset[5], iso_td.offset[6], iso_td.offset[7],
6435973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner           ohci->frame_number, starting_frame,
6445973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner           frame_count, relative_frame_number,
6458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           OHCI_BM(iso_td.flags, TD_DI), OHCI_BM(iso_td.flags, TD_CC));
6468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
6478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (relative_frame_number < 0) {
6498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: ISO_TD R=%d < 0\n", relative_frame_number);
6508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 1;
6518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (relative_frame_number > frame_count) {
6528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* ISO TD expired - retire the TD to the Done Queue and continue with
6538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           the next ISO TD of the same ED */
6545973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner        dprintf("usb-ohci: ISO_TD R=%d > FC=%d\n", relative_frame_number,
6558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               frame_count);
6568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ed->head &= ~OHCI_DPTR_MASK;
6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ed->head |= (iso_td.next & OHCI_DPTR_MASK);
6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        iso_td.next = ohci->done;
6608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->done = addr;
6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        i = OHCI_BM(iso_td.flags, TD_DI);
6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (i < ohci->done_count)
6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->done_count = i;
6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ohci_put_iso_td(ohci, addr, &iso_td);
6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
6668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dir = OHCI_BM(ed->flags, ED_D);
6698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (dir) {
6708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_TD_DIR_IN:
6718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        str = "in";
6728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pid = USB_TOKEN_IN;
6738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
6748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_TD_DIR_OUT:
6758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        str = "out";
6768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pid = USB_TOKEN_OUT;
6778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
6788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_TD_DIR_SETUP:
6798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        str = "setup";
6808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pid = USB_TOKEN_SETUP;
6818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
6828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
6838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        printf("usb-ohci: Bad direction %d\n", dir);
6848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 1;
6858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!iso_td.bp || !iso_td.be) {
6888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        printf("usb-ohci: ISO_TD bp 0x%.8x be 0x%.8x\n", iso_td.bp, iso_td.be);
6898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 1;
6908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    start_offset = iso_td.offset[relative_frame_number];
6938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    next_offset = iso_td.offset[relative_frame_number + 1];
6948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6955973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) ||
6965973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner        ((relative_frame_number < frame_count) &&
6978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project         !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) {
6988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        printf("usb-ohci: ISO_TD cc != not accessed 0x%.8x 0x%.8x\n",
6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               start_offset, next_offset);
7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 1;
7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((relative_frame_number < frame_count) && (start_offset > next_offset)) {
7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        printf("usb-ohci: ISO_TD start_offset=0x%.8x > next_offset=0x%.8x\n",
7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                start_offset, next_offset);
7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 1;
7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((start_offset & 0x1000) == 0) {
7108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        start_addr = (iso_td.bp & OHCI_PAGE_MASK) |
7118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            (start_offset & OHCI_OFFSET_MASK);
7128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
7138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        start_addr = (iso_td.be & OHCI_PAGE_MASK) |
7148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            (start_offset & OHCI_OFFSET_MASK);
7158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (relative_frame_number < frame_count) {
7188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        end_offset = next_offset - 1;
7198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if ((end_offset & 0x1000) == 0) {
7208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            end_addr = (iso_td.bp & OHCI_PAGE_MASK) |
7218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                (end_offset & OHCI_OFFSET_MASK);
7228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
7238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            end_addr = (iso_td.be & OHCI_PAGE_MASK) |
7248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                (end_offset & OHCI_OFFSET_MASK);
7258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
7278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Last packet in the ISO TD */
7288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        end_addr = iso_td.be;
7298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) {
7328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        len = (end_addr & OHCI_OFFSET_MASK) + 0x1001
7338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            - (start_addr & OHCI_OFFSET_MASK);
7348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
7358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        len = end_addr - start_addr + 1;
7368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (len && dir != OHCI_TD_DIR_IN) {
7395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 0);
7408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (completion) {
7438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = ohci->usb_packet.len;
7448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
7458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = USB_RET_NODEV;
7468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < ohci->num_ports; i++) {
7478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            dev = ohci->rhport[i].port.dev;
7488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
7498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                continue;
7508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.pid = pid;
7518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
7528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
7538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.data = ohci->usb_buf;
7548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.len = len;
7558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.complete_cb = ohci_async_complete_packet;
7568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.complete_opaque = ohci;
7578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ret = dev->handle_packet(dev, &ohci->usb_packet);
7588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (ret != USB_RET_NODEV)
7598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
7608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7615973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner
7628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ret == USB_RET_ASYNC) {
7638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 1;
7648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
7658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_ISOCH
7688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n",
7698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           start_offset, end_offset, start_addr, end_addr, str, len, ret);
7708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
7718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Writeback */
7738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
7748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* IN transfer succeeded */
7755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 1);
7768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
7778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    OHCI_CC_NOERROR);
7788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);
7798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (dir == OHCI_TD_DIR_OUT && ret == len) {
7808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* OUT transfer succeeded */
7818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
7828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    OHCI_CC_NOERROR);
7838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0);
7848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
7858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ret > (ssize_t) len) {
7868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            printf("usb-ohci: DataOverrun %d > %zu\n", ret, len);
7878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
7888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        OHCI_CC_DATAOVERRUN);
7898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
7908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        len);
7918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else if (ret >= 0) {
7928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            printf("usb-ohci: DataUnderrun %d\n", ret);
7938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
7948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        OHCI_CC_DATAUNDERRUN);
7958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
7968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            switch (ret) {
7978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case USB_RET_NODEV:
7988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
7998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            OHCI_CC_DEVICENOTRESPONDING);
8008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
8018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            0);
8028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
8038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case USB_RET_NAK:
8048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case USB_RET_STALL:
8058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                printf("usb-ohci: got NAK/STALL %d\n", ret);
8068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
8078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            OHCI_CC_STALL);
8088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
8098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            0);
8108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
8118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            default:
8128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                printf("usb-ohci: Bad device response %d\n", ret);
8138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
8148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            OHCI_CC_UNDEXPETEDPID);
8158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
8168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
8178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
8188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (relative_frame_number == frame_count) {
8218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Last data packet of ISO TD - retire the TD to the Done Queue */
8228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR);
8238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ed->head &= ~OHCI_DPTR_MASK;
8248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ed->head |= (iso_td.next & OHCI_DPTR_MASK);
8258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        iso_td.next = ohci->done;
8268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->done = addr;
8278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        i = OHCI_BM(iso_td.flags, TD_DI);
8288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (i < ohci->done_count)
8298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->done_count = i;
8308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ohci_put_iso_td(ohci, addr, &iso_td);
8328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 1;
8338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
8348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Service a transport descriptor.
8368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   Returns nonzero to terminate processing of this endpoint.  */
8378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
8398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
8408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int dir;
8418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size_t len = 0;
8428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const char *str = NULL;
8438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int pid;
8448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ret;
8458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
8468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    USBDevice *dev;
8478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct ohci_td td;
8488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t addr;
8498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int flag_r;
8508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int completion;
8518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    addr = ed->head & OHCI_DPTR_MASK;
8538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* See if this TD has already been submitted to the device.  */
8548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    completion = (addr == ohci->async_td);
8558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (completion && !ohci->async_complete) {
8568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_PACKET
8578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("Skipping async TD\n");
8588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
8598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 1;
8608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!ohci_read_td(ohci, addr, &td)) {
8628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        fprintf(stderr, "usb-ohci: TD read error at %x\n", addr);
8638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
8648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dir = OHCI_BM(ed->flags, ED_D);
8678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (dir) {
8688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_TD_DIR_OUT:
8698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_TD_DIR_IN:
8708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Same value.  */
8718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
8728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
8738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dir = OHCI_BM(td.flags, TD_DP);
8748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
8758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
8778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (dir) {
8788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_TD_DIR_IN:
8798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        str = "in";
8808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pid = USB_TOKEN_IN;
8818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
8828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_TD_DIR_OUT:
8838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        str = "out";
8848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pid = USB_TOKEN_OUT;
8858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
8868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_TD_DIR_SETUP:
8878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        str = "setup";
8888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        pid = USB_TOKEN_SETUP;
8898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
8908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
8918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        fprintf(stderr, "usb-ohci: Bad direction\n");
8928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 1;
8938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
8948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (td.cbp && td.be) {
8958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if ((td.cbp & 0xfffff000) != (td.be & 0xfffff000)) {
8968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            len = (td.be & 0xfff) + 0x1001 - (td.cbp & 0xfff);
8978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
8988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            len = (td.be - td.cbp) + 1;
8998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
9008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (len && dir != OHCI_TD_DIR_IN && !completion) {
9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ohci_copy_td(ohci, &td, ohci->usb_buf, len, 0);
9038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
9048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
9058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    flag_r = (td.flags & OHCI_TD_R) != 0;
9078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_PACKET
9088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dprintf(" TD @ 0x%.8x %u bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
9098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            addr, len, str, flag_r, td.cbp, td.be);
9108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (len > 0 && dir != OHCI_TD_DIR_IN) {
9128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("  data:");
9138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < len; i++)
9148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            printf(" %.2x", ohci->usb_buf[i]);
9158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("\n");
9168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
9178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
9188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (completion) {
9198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = ohci->usb_packet.len;
9208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->async_td = 0;
9218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->async_complete = 0;
9228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
9238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = USB_RET_NODEV;
9248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < ohci->num_ports; i++) {
9258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            dev = ohci->rhport[i].port.dev;
9268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
9278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                continue;
9288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (ohci->async_td) {
9308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                /* ??? The hardware should allow one active packet per
9318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                   endpoint.  We only allow one active packet per controller.
9328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                   This should be sufficient as long as devices respond in a
9338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                   timely manner.
9348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                 */
9358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_PACKET
9368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                dprintf("Too many pending packets\n");
9378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
9388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                return 1;
9398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
9408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.pid = pid;
9418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
9428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
9438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.data = ohci->usb_buf;
9448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.len = len;
9458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.complete_cb = ohci_async_complete_packet;
9468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->usb_packet.complete_opaque = ohci;
9478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ret = dev->handle_packet(dev, &ohci->usb_packet);
9488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (ret != USB_RET_NODEV)
9498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
9508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
9518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_PACKET
9528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("ret=%d\n", ret);
9538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
9548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ret == USB_RET_ASYNC) {
9558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->async_td = addr;
9568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 1;
9578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
9588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
9598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret >= 0) {
9608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (dir == OHCI_TD_DIR_IN) {
9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ohci_copy_td(ohci, &td, ohci->usb_buf, ret, 1);
9628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_PACKET
9638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            dprintf("  data:");
9648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            for (i = 0; i < ret; i++)
9658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                printf(" %.2x", ohci->usb_buf[i]);
9668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            dprintf("\n");
9678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
9688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
9698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ret = len;
9708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
9718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
9728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Writeback */
9748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
9758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Transmission succeeded.  */
9768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ret == len) {
9778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            td.cbp = 0;
9788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
9798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            td.cbp += ret;
9808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if ((td.cbp & 0xfff) + ret > 0xfff) {
9818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                td.cbp &= 0xfff;
9828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                td.cbp |= td.be & ~0xfff;
9838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
9848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
9858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        td.flags |= OHCI_TD_T1;
9868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        td.flags ^= OHCI_TD_T0;
9878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR);
9888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        OHCI_SET_BM(td.flags, TD_EC, 0);
9898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
9908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ed->head &= ~OHCI_ED_C;
9918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (td.flags & OHCI_TD_T0)
9928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ed->head |= OHCI_ED_C;
9938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
9948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ret >= 0) {
9958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            dprintf("usb-ohci: Underrun\n");
9968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN);
9978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
9988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            switch (ret) {
9998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case USB_RET_NODEV:
10008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING);
10018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case USB_RET_NAK:
10028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                dprintf("usb-ohci: got NAK\n");
10038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                return 1;
10048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case USB_RET_STALL:
10058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                dprintf("usb-ohci: got STALL\n");
10068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL);
10078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
10088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case USB_RET_BABBLE:
10098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                dprintf("usb-ohci: got BABBLE\n");
10108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
10118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
10128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            default:
10138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                fprintf(stderr, "usb-ohci: Bad device response %d\n", ret);
10148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID);
10158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                OHCI_SET_BM(td.flags, TD_EC, 3);
10168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
10178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
10188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
10198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ed->head |= OHCI_ED_H;
10208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
10218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Retire this TD */
10238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ed->head &= ~OHCI_DPTR_MASK;
10248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ed->head |= td.next & OHCI_DPTR_MASK;
10258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    td.next = ohci->done;
10268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->done = addr;
10278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    i = OHCI_BM(td.flags, TD_DI);
10288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (i < ohci->done_count)
10298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->done_count = i;
10305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ohci_put_td(ohci, addr, &td);
10318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
10328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
10338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Service an endpoint list.  Returns nonzero if active TD were found.  */
10358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
10368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
10378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct ohci_ed ed;
10388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t next_ed;
10398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t cur;
10408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int active;
10418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    active = 0;
10438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (head == 0)
10458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
10468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (cur = head; cur; cur = next_ed) {
10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!ohci_read_ed(ohci, cur, &ed)) {
10498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            fprintf(stderr, "usb-ohci: ED read error at %x\n", cur);
10508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 0;
10518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
10528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        next_ed = ed.next & OHCI_DPTR_MASK;
10548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) {
10568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uint32_t addr;
10578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* Cancel pending packets for ED that have been paused.  */
10588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            addr = ed.head & OHCI_DPTR_MASK;
10598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (ohci->async_td && addr == ohci->async_td) {
10608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                usb_cancel_packet(&ohci->usb_packet);
10618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                ohci->async_td = 0;
10628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
10638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            continue;
10648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
10658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        while ((ed.head & OHCI_DPTR_MASK) != ed.tail) {
10678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_PACKET
10688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            dprintf("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u "
10698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    "h=%u c=%u\n  head=0x%.8x tailp=0x%.8x next=0x%.8x\n", cur,
10708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN),
10718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0,
10728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0,
10738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    OHCI_BM(ed.flags, ED_MPS), (ed.head & OHCI_ED_H) != 0,
10748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK,
10758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK);
10768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
10778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            active = 1;
10788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if ((ed.flags & OHCI_ED_F) == 0) {
10808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (ohci_service_td(ohci, &ed))
10818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    break;
10828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            } else {
10838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                /* Handle isochronous endpoints */
10848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (ohci_service_iso_td(ohci, &ed, completion))
10858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    break;
10868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
10878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
10888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ohci_put_ed(ohci, cur, &ed);
10908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
10918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return active;
10938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
10948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
10958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Generate a SOF event, and set a timer for EOF */
10968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_sof(OHCIState *ohci)
10978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
10985973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    ohci->sof_time = qemu_get_clock_ns(vm_clock);
10998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_mod_timer(ohci->eof_timer, ohci->sof_time + usb_frame_time);
11008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_set_interrupt(ohci, OHCI_INTR_SF);
11018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Process Control and Bulk lists.  */
11048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_process_lists(OHCIState *ohci, int completion)
11058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
11078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head)
11088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project          dprintf("usb-ohci: head %x, cur %x\n",
11098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                          ohci->ctrl_head, ohci->ctrl_cur);
11108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) {
11118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->ctrl_cur = 0;
11128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->status &= ~OHCI_STATUS_CLF;
11138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
11148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) {
11178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) {
11188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->bulk_cur = 0;
11198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->status &= ~OHCI_STATUS_BLF;
11208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
11218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Do frame processing on frame boundary */
11258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_frame_boundary(void *opaque)
11268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIState *ohci = opaque;
11288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct ohci_hcca hcca;
11298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ohci_read_hcca(ohci, ohci->hcca, &hcca);
11318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Process all the lists at the end of the frame */
11338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci->ctl & OHCI_CTL_PLE) {
11348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int n;
11358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        n = ohci->frame_number & 0x1f;
11378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0);
11388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Cancel all pending packets if either of the lists has been disabled.  */
11418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci->async_td &&
11428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
11438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        usb_cancel_packet(&ohci->usb_packet);
11448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->async_td = 0;
11458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->old_ctl = ohci->ctl;
11478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_process_lists(ohci, 0);
11488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Frame boundary, so do EOF stuf here */
11508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->frt = ohci->fit;
11518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* XXX: endianness */
11538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->frame_number = (ohci->frame_number + 1) & 0xffff;
11548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    hcca.frame = cpu_to_le32(ohci->frame_number);
11558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) {
11578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!ohci->done)
11588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            abort();
11598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ohci->intr & ohci->intr_status)
11608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->done |= 1;
11618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        hcca.done = cpu_to_le32(ohci->done);
11628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->done = 0;
11638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->done_count = 7;
11648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_set_interrupt(ohci, OHCI_INTR_WD);
11658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci->done_count != 7 && ohci->done_count != 0)
11688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->done_count--;
11698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Do SOF stuff here */
11718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_sof(ohci);
11728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Writeback HCCA */
11745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ohci_put_hcca(ohci, ohci->hcca, &hcca);
11758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Start sending SOF tokens across the USB bus, lists are processed in
11788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * next frame
11798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
11808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int ohci_bus_start(OHCIState *ohci)
11818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
11825973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    ohci->eof_timer = qemu_new_timer_ns(vm_clock,
11838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    ohci_frame_boundary,
11848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    ohci);
11858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci->eof_timer == NULL) {
11875973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner        fprintf(stderr, "usb-ohci: %s: qemu_new_timer_ns failed\n", ohci->name);
11888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* TODO: Signal unrecoverable error */
11898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
11908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
11918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    dprintf("usb-ohci: %s: USB Operational\n", ohci->name);
11938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_sof(ohci);
11958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 1;
11978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
11988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
11998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Stop sending SOF tokens on the bus */
12008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_bus_stop(OHCIState *ohci)
12018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci->eof_timer)
12038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_del_timer(ohci->eof_timer);
12048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->eof_timer = NULL;
12058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Sets a flag in a port status register but only set it if the port is
12088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * connected, if not set ConnectStatusChange flag. If flag is enabled
12098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * return 1.
12108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
12118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val)
12128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ret = 1;
12148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* writing a 0 has no effect */
12168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val == 0)
12178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
12188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* If CurrentConnectStatus is cleared we set
12208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * ConnectStatusChange
12218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
12228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) {
12238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->rhport[i].ctrl |= OHCI_PORT_CSC;
12248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ohci->rhstatus & OHCI_RHS_DRWE) {
12258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* TODO: CSC is a wakeup event */
12268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
12278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
12288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
12298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci->rhport[i].ctrl & val)
12318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ret = 0;
12328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* set the bit */
12348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->rhport[i].ctrl |= val;
12358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return ret;
12378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Set the frame interval - frame interval toggle is manipulated by the hcd only */
12408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_set_frame_interval(OHCIState *ohci, uint16_t val)
12418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    val &= OHCI_FMI_FI;
12438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val != ohci->fi) {
12458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: %s: FrameInterval = 0x%x (%u)\n",
12468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci->name, ohci->fi, ohci->fi);
12478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
12488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->fi = val;
12508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_port_power(OHCIState *ohci, int i, int p)
12538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (p) {
12558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->rhport[i].ctrl |= OHCI_PORT_PPS;
12568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
12578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS|
12588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    OHCI_PORT_CCS|
12598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    OHCI_PORT_PSS|
12608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    OHCI_PORT_PRS);
12618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
12628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Set HcControlRegister */
12658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_set_ctl(OHCIState *ohci, uint32_t val)
12668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t old_state;
12688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t new_state;
12698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    old_state = ohci->ctl & OHCI_CTL_HCFS;
12718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->ctl = val;
12728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    new_state = ohci->ctl & OHCI_CTL_HCFS;
12738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* no state change */
12758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (old_state == new_state)
12768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
12778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (new_state) {
12798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_USB_OPERATIONAL:
12808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_bus_start(ohci);
12818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
12828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_USB_SUSPEND:
12838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_bus_stop(ohci);
12848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: %s: USB Suspended\n", ohci->name);
12858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
12868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_USB_RESUME:
12878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: %s: USB Resume\n", ohci->name);
12888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
12898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case OHCI_USB_RESET:
12908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_reset(ohci);
12918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: %s: USB Reset\n", ohci->name);
12928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
12938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
12948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
12958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
12968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t ohci_get_frame_remaining(OHCIState *ohci)
12978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
12988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint16_t fr;
12998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int64_t tks;
13008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL)
13028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return (ohci->frt << 31);
13038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Being in USB operational state guarnatees sof_time was
13058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * set already.
13068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
13075973c775c853e26f684de58ad28c267281aaffd6David 'Digit' Turner    tks = qemu_get_clock_ns(vm_clock) - ohci->sof_time;
13088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* avoid muldiv if possible */
13108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (tks >= usb_frame_time)
13118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return (ohci->frt << 31);
13128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    tks = muldiv64(1, tks, usb_bit_time);
13148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    fr = (uint16_t)(ohci->fi - tks);
13158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return (ohci->frt << 31) | fr;
13178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
13188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Set root hub status */
13218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_set_hub_status(OHCIState *ohci, uint32_t val)
13228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
13238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t old_state;
13248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    old_state = ohci->rhstatus;
13268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* write 1 to clear OCIC */
13288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val & OHCI_RHS_OCIC)
13298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->rhstatus &= ~OHCI_RHS_OCIC;
13308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val & OHCI_RHS_LPS) {
13328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int i;
13338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < ohci->num_ports; i++)
13358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci_port_power(ohci, i, 0);
13368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: powered down all ports\n");
13378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
13388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val & OHCI_RHS_LPSC) {
13408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int i;
13418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < ohci->num_ports; i++)
13438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci_port_power(ohci, i, 1);
13448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: powered up all ports\n");
13458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
13468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val & OHCI_RHS_DRWE)
13488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->rhstatus |= OHCI_RHS_DRWE;
13498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val & OHCI_RHS_CRWE)
13518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->rhstatus &= ~OHCI_RHS_DRWE;
13528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (old_state != ohci->rhstatus)
13548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
13558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
13568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Set root hub port status */
13588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
13598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
13608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t old_state;
13618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIPort *port;
13628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    port = &ohci->rhport[portnum];
13648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    old_state = port->ctrl;
13658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */
13678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val & OHCI_PORT_WTC)
13688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        port->ctrl &= ~(val & OHCI_PORT_WTC);
13698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val & OHCI_PORT_CCS)
13718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        port->ctrl &= ~OHCI_PORT_PES;
13728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES);
13748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS))
13768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: port %d: SUSPEND\n", portnum);
13778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) {
13798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: port %d: RESET\n", portnum);
13808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        usb_send_msg(port->port.dev, USB_MSG_RESET);
13818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        port->ctrl &= ~OHCI_PORT_PRS;
13828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* ??? Should this also set OHCI_PORT_PESC.  */
13838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC;
13848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
13858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Invert order here to ensure in ambiguous case, device is
13878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     * powered up...
13888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project     */
13898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val & OHCI_PORT_LSDA)
13908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_port_power(ohci, portnum, 0);
13918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (val & OHCI_PORT_PPS)
13928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_port_power(ohci, portnum, 1);
13938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (old_state != port->ctrl)
13958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_set_interrupt(ohci, OHCI_INTR_RHSC);
13968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
13978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return;
13988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
13998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
14018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
14028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIState *ohci = ptr;
14035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t retval;
14048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
14058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Only aligned reads are allowed on OHCI */
14068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (addr & 3) {
14078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        fprintf(stderr, "usb-ohci: Mis-aligned read\n");
14088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0xffffffff;
14095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
14108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* HcRhPortStatus */
14115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        retval = ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS;
14125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
14135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        switch (addr >> 2) {
14145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 0: /* HcRevision */
14155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = 0x10;
14165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 1: /* HcControl */
14195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->ctl;
14205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 2: /* HcCommandStatus */
14235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->status;
14245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 3: /* HcInterruptStatus */
14275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->intr_status;
14285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 4: /* HcInterruptEnable */
14315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 5: /* HcInterruptDisable */
14325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->intr;
14335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 6: /* HcHCCA */
14365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->hcca;
14375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 7: /* HcPeriodCurrentED */
14405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->per_cur;
14415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 8: /* HcControlHeadED */
14445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->ctrl_head;
14455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 9: /* HcControlCurrentED */
14485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->ctrl_cur;
14495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 10: /* HcBulkHeadED */
14525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->bulk_head;
14535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 11: /* HcBulkCurrentED */
14565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->bulk_cur;
14575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 12: /* HcDoneHead */
14605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->done;
14615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 13: /* HcFmInterretval */
14645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi);
14655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 14: /* HcFmRemaining */
14685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci_get_frame_remaining(ohci);
14695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 15: /* HcFmNumber */
14725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->frame_number;
14735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 16: /* HcPeriodicStart */
14765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->pstart;
14775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 17: /* HcLSThreshold */
14805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->lst;
14815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 18: /* HcRhDescriptorA */
14845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->rhdesc_a;
14855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 19: /* HcRhDescriptorB */
14885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->rhdesc_b;
14895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 20: /* HcRhStatus */
14925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->rhstatus;
14935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* PXA27x specific registers */
14965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 24: /* HcStatus */
14975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->hstatus & ohci->hmask;
14985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
14995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 25: /* HcHReset */
15015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->hreset;
15025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 26: /* HcHInterruptEnable */
15055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->hmask;
15065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 27: /* HcHInterruptTest */
15095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = ohci->htest;
15105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        default:
15135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr);
15145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            retval = 0xffffffff;
15155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
15168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
15178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef TARGET_WORDS_BIGENDIAN
15195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    retval = bswap32(retval);
15205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
15215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return retval;
15228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
15238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
15258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
15268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIState *ohci = ptr;
15278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef TARGET_WORDS_BIGENDIAN
15295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    val = bswap32(val);
15305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
15318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Only aligned reads are allowed on OHCI */
15338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (addr & 3) {
15348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        fprintf(stderr, "usb-ohci: Mis-aligned write\n");
15358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
15368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
15378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) {
15398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* HcRhPortStatus */
15408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_port_set_status(ohci, (addr - 0x54) >> 2, val);
15418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
15428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
15438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (addr >> 2) {
15458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 1: /* HcControl */
15468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_set_ctl(ohci, val);
15478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
15488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 2: /* HcCommandStatus */
15508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* SOC is read-only */
15518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = (val & ~OHCI_STATUS_SOC);
15528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Bits written as '0' remain unchanged in the register */
15548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->status |= val;
15558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ohci->status & OHCI_STATUS_HCR)
15578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci_reset(ohci);
15588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
15598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 3: /* HcInterruptStatus */
15618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->intr_status &= ~val;
15628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_intr_update(ohci);
15638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
15648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 4: /* HcInterruptEnable */
15668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->intr |= val;
15678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_intr_update(ohci);
15688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
15698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 5: /* HcInterruptDisable */
15718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->intr &= ~val;
15728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_intr_update(ohci);
15738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
15748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 6: /* HcHCCA */
15768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->hcca = val & OHCI_HCCA_MASK;
15778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
15788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 8: /* HcControlHeadED */
15808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->ctrl_head = val & OHCI_EDPTR_MASK;
15818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
15828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 9: /* HcControlCurrentED */
15848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->ctrl_cur = val & OHCI_EDPTR_MASK;
15858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
15868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 10: /* HcBulkHeadED */
15888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->bulk_head = val & OHCI_EDPTR_MASK;
15898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
15908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 11: /* HcBulkCurrentED */
15928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->bulk_cur = val & OHCI_EDPTR_MASK;
15938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
15948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
15958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 13: /* HcFmInterval */
15968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16;
15978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->fit = (val & OHCI_FMI_FIT) >> 31;
15988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_set_frame_interval(ohci, val);
15998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 15: /* HcFmNumber */
16028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 16: /* HcPeriodicStart */
16058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->pstart = val & 0xffff;
16068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 17: /* HcLSThreshold */
16098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->lst = val & 0xffff;
16108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 18: /* HcRhDescriptorA */
16138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK;
16148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK;
16158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 19: /* HcRhDescriptorB */
16188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 20: /* HcRhStatus */
16218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci_set_hub_status(ohci, val);
16228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* PXA27x specific registers */
16258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 24: /* HcStatus */
16268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->hstatus &= ~(val & ohci->hmask);
16278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 25: /* HcHReset */
16298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->hreset = val & ~OHCI_HRESET_FSBIR;
16308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (val & OHCI_HRESET_FSBIR)
16318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ohci_reset(ohci);
16328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 26: /* HcHInterruptEnable */
16358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->hmask = val;
16368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 27: /* HcHInterruptTest */
16398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ohci->htest = val;
16408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
16438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr);
16448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
16458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
16468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
16478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Only dword reads are defined on OHCI register space */
16498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUReadMemoryFunc *ohci_readfn[3]={
16508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_mem_read,
16518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_mem_read,
16528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_mem_read
16538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
16548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Only dword writes are defined on OHCI register space */
16568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUWriteMemoryFunc *ohci_writefn[3]={
16578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_mem_write,
16588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_mem_write,
16598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_mem_write
16608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
16618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
16635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          qemu_irq irq, enum ohci_type type,
16645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          const char *name, uint32_t localmem_base)
16658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
16668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
16678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (usb_frame_time == 0) {
16698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef OHCI_TIME_WARP
1670a7fb77d6eca56e61e94f62e7deb4120b60b1e919David 'Digit' Turner        usb_frame_time = get_ticks_per_sec();
1671a7fb77d6eca56e61e94f62e7deb4120b60b1e919David 'Digit' Turner        usb_bit_time = muldiv64(1, get_ticks_per_sec(), USB_HZ/1000);
16728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
1673a7fb77d6eca56e61e94f62e7deb4120b60b1e919David 'Digit' Turner        usb_frame_time = muldiv64(1, get_ticks_per_sec(), 1000);
1674a7fb77d6eca56e61e94f62e7deb4120b60b1e919David 'Digit' Turner        if (get_ticks_per_sec() >= USB_HZ) {
1675a7fb77d6eca56e61e94f62e7deb4120b60b1e919David 'Digit' Turner            usb_bit_time = muldiv64(1, get_ticks_per_sec(), USB_HZ);
16768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
16778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            usb_bit_time = 1;
16788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
16798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
16808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dprintf("usb-ohci: usb_bit_time=%lli usb_frame_time=%lli\n",
16818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                usb_frame_time, usb_bit_time);
16828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
16838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci);
16855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ohci->localmem_base = localmem_base;
16868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->name = name;
16878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->irq = irq;
16898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->type = type;
16908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->num_ports = num_ports;
16928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < num_ports; i++) {
16938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach);
16948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
16958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
16968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->async_td = 0;
16975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_register_reset(ohci_reset, 0, ohci);
16988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci_reset(ohci);
16998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
17008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct {
17028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PCIDevice pci_dev;
17038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIState state;
17048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} OHCIPCIState;
17058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void ohci_mapfunc(PCIDevice *pci_dev, int i,
17078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uint32_t addr, uint32_t size, int type)
17088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
17098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIPCIState *ohci = (OHCIPCIState *)pci_dev;
17108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cpu_register_physical_memory(addr, size, ohci->state.mem);
17118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
17128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn)
17148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
17158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIPCIState *ohci;
17168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci = (OHCIPCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci),
17188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                               devfn, NULL, NULL);
17198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ohci == NULL) {
17208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        fprintf(stderr, "usb-ohci: Failed to register PCI device\n");
17218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
17228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
17238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_config_set_vendor_id(ohci->pci_dev.config, PCI_VENDOR_ID_APPLE);
17255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_config_set_device_id(ohci->pci_dev.config,
17265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                             PCI_DEVICE_ID_APPLE_IPID_USB);
17278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->pci_dev.config[0x09] = 0x10; /* OHCI */
17285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_config_set_class(ohci->pci_dev.config, PCI_CLASS_SERIAL_USB);
17298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
17308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0],
17325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                  OHCI_TYPE_PCI, ohci->pci_dev.name, 0);
17338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pci_register_bar((struct PCIDevice *)ohci, 0, 256,
17358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                           PCI_ADDRESS_SPACE_MEM, ohci_mapfunc);
17368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
17378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectvoid usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
17398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                       qemu_irq irq)
17408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
17418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
17428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    usb_ohci_init(ohci, num_ports, devfn, irq,
17445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                  OHCI_TYPE_PXA, "OHCI USB", 0);
17458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
17465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cpu_register_physical_memory(base, 0x1000, ohci->mem);
17478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
17485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid usb_ohci_init_sm501(uint32_t mmio_base, uint32_t localmem_base,
17505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         int num_ports, int devfn, qemu_irq irq)
17515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
17525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
17535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    usb_ohci_init(ohci, num_ports, devfn, irq,
17555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                  OHCI_TYPE_SM501, "OHCI USB", localmem_base);
17565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cpu_register_physical_memory(mmio_base, 0x1000, ohci->mem);
17585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
17595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1760