Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
qemu
提交
b4dabf95
Q
qemu
项目概览
openeuler
/
qemu
通知
10
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Q
qemu
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
b4dabf95
编写于
7月 19, 2011
作者:
A
Anthony Liguori
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'kraxel/usb.19' into staging
上级
de20fbca
3dc345d5
变更
13
显示空白变更内容
内联
并排
Showing
13 changed file
with
523 addition
and
235 deletion
+523
-235
docs/ich9-ehci-uhci.cfg
docs/ich9-ehci-uhci.cfg
+37
-0
docs/usb2.txt
docs/usb2.txt
+28
-5
hw/milkymist-softusb.c
hw/milkymist-softusb.c
+7
-2
hw/pci_ids.h
hw/pci_ids.h
+8
-0
hw/usb-bt.c
hw/usb-bt.c
+12
-12
hw/usb-bus.c
hw/usb-bus.c
+40
-6
hw/usb-ehci.c
hw/usb-ehci.c
+196
-74
hw/usb-hub.c
hw/usb-hub.c
+17
-73
hw/usb-musb.c
hw/usb-musb.c
+16
-8
hw/usb-ohci.c
hw/usb-ohci.c
+64
-25
hw/usb-uhci.c
hw/usb-uhci.c
+75
-20
hw/usb.c
hw/usb.c
+6
-7
hw/usb.h
hw/usb.h
+17
-3
未找到文件。
docs/ich9-ehci-uhci.cfg
0 → 100644
浏览文件 @
b4dabf95
###########################################################################
#
# You can pass this file directly to qemu using the -readconfig
# command line switch.
#
# This config file creates a EHCI adapter with companion UHCI
# controllers as multifunction device in PCI slot "1d".
#
# Specify "bus=ehci.0" when creating usb devices to hook them up
# there.
#
[device "ehci"]
driver = "ich9-usb-ehci1"
addr = "1d.7"
multifunction = "on"
[device "uhci-1"]
driver = "ich9-usb-uhci1"
addr = "1d.0"
multifunction = "on"
masterbus = "ehci.0"
firstport = "0"
[device "uhci-2"]
driver = "ich9-usb-uhci2"
addr = "1d.1"
multifunction = "on"
masterbus = "ehci.0"
firstport = "2"
[device "uhci-3"]
driver = "ich9-usb-uhci3"
addr = "1d.2"
multifunction = "on"
masterbus = "ehci.0"
firstport = "4"
docs/usb2.txt
浏览文件 @
b4dabf95
...
...
@@ -2,11 +2,13 @@
USB 2.0 Quick Start
===================
The QEMU EHCI Adapter does *not* support companion controllers. That
implies there are two completely separate USB busses: One USB 1.1 bus
driven by the UHCI controller and one USB 2.0 bus driven by the EHCI
controller. Devices must be attached to the correct controller
manually.
The QEMU EHCI Adapter can be used with and without companion
controllers. See below for the companion controller mode.
When not running in companion controller mode there are two completely
separate USB busses: One USB 1.1 bus driven by the UHCI controller and
one USB 2.0 bus driven by the EHCI controller. Devices must be
attached to the correct controller manually.
The '-usb' switch will make qemu create the UHCI controller as part of
the PIIX3 chipset. The USB 1.1 bus will carry the name "usb.0".
...
...
@@ -32,6 +34,27 @@ This attaches a usb tablet to the UHCI adapter and a usb mass storage
device to the EHCI adapter.
Companion controller support
----------------------------
Companion controller support has been added recently. The operational
model described above with two completely separate busses still works
fine. Additionally the UHCI and OHCI controllers got the ability to
attach to a usb bus created by EHCI as companion controllers. This is
done by specifying the masterbus and firstport properties. masterbus
specifies the bus name the controller should attach to. firstport
specifies the first port the controller should attach to, which is
needed as usually one ehci controller with six ports has three uhci
companion controllers with two ports each.
There is a config file in docs which will do all this for you, just
try ...
qemu -readconfig docs/ich9-ehci-uhci.cfg
... then use "bus=ehci.0" to assign your usb devices to that bus.
More USB tips & tricks
======================
...
...
hw/milkymist-softusb.c
浏览文件 @
b4dabf95
...
...
@@ -247,16 +247,21 @@ static void softusb_attach(USBPort *port)
{
}
static
void
softusb_device_destroy
(
USBBus
*
bus
,
USBDevice
*
dev
)
static
void
softusb_detach
(
USBPort
*
port
)
{
}
static
void
softusb_child_detach
(
USBPort
*
port
,
USBDevice
*
child
)
{
}
static
USBPortOps
softusb_ops
=
{
.
attach
=
softusb_attach
,
.
detach
=
softusb_detach
,
.
child_detach
=
softusb_child_detach
,
};
static
USBBusOps
softusb_bus_ops
=
{
.
device_destroy
=
softusb_device_destroy
,
};
static
void
milkymist_softusb_reset
(
DeviceState
*
d
)
...
...
hw/pci_ids.h
浏览文件 @
b4dabf95
...
...
@@ -109,6 +109,14 @@
#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937
#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938
#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939
#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a
#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
#define PCI_VENDOR_ID_XEN 0x5853
#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
hw/usb-bt.c
浏览文件 @
b4dabf95
...
...
@@ -99,13 +99,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.
eps
=
(
USBDescEndpoint
[])
{
{
.
bEndpointAddress
=
USB_DIR_OUT
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0
,
.
bInterval
=
0x01
,
},
{
.
bEndpointAddress
=
USB_DIR_IN
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0
,
.
bInterval
=
0x01
,
},
...
...
@@ -120,13 +120,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.
eps
=
(
USBDescEndpoint
[])
{
{
.
bEndpointAddress
=
USB_DIR_OUT
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0x09
,
.
bInterval
=
0x01
,
},
{
.
bEndpointAddress
=
USB_DIR_IN
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0x09
,
.
bInterval
=
0x01
,
},
...
...
@@ -141,13 +141,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.
eps
=
(
USBDescEndpoint
[])
{
{
.
bEndpointAddress
=
USB_DIR_OUT
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0x11
,
.
bInterval
=
0x01
,
},
{
.
bEndpointAddress
=
USB_DIR_IN
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0x11
,
.
bInterval
=
0x01
,
},
...
...
@@ -162,13 +162,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.
eps
=
(
USBDescEndpoint
[])
{
{
.
bEndpointAddress
=
USB_DIR_OUT
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0x19
,
.
bInterval
=
0x01
,
},
{
.
bEndpointAddress
=
USB_DIR_IN
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0x19
,
.
bInterval
=
0x01
,
},
...
...
@@ -183,13 +183,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.
eps
=
(
USBDescEndpoint
[])
{
{
.
bEndpointAddress
=
USB_DIR_OUT
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0x21
,
.
bInterval
=
0x01
,
},
{
.
bEndpointAddress
=
USB_DIR_IN
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0x21
,
.
bInterval
=
0x01
,
},
...
...
@@ -204,13 +204,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.
eps
=
(
USBDescEndpoint
[])
{
{
.
bEndpointAddress
=
USB_DIR_OUT
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0x31
,
.
bInterval
=
0x01
,
},
{
.
bEndpointAddress
=
USB_DIR_IN
|
USB_SCO_EP
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
NT
,
.
bmAttributes
=
USB_ENDPOINT_XFER_I
SOC
,
.
wMaxPacketSize
=
0x31
,
.
bInterval
=
0x01
,
},
...
...
hw/usb-bus.c
浏览文件 @
b4dabf95
...
...
@@ -82,12 +82,10 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
static
int
usb_qdev_exit
(
DeviceState
*
qdev
)
{
USBDevice
*
dev
=
DO_UPCAST
(
USBDevice
,
qdev
,
qdev
);
USBBus
*
bus
=
usb_bus_from_device
(
dev
);
if
(
dev
->
attached
)
{
usb_device_detach
(
dev
);
}
bus
->
ops
->
device_destroy
(
bus
,
dev
);
if
(
dev
->
info
->
handle_destroy
)
{
dev
->
info
->
handle_destroy
(
dev
);
}
...
...
@@ -140,19 +138,55 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name)
return
dev
;
}
void
usb_register_port
(
USBBus
*
bus
,
USBPort
*
port
,
void
*
opaque
,
int
index
,
static
void
usb_fill_port
(
USBPort
*
port
,
void
*
opaque
,
int
index
,
USBPortOps
*
ops
,
int
speedmask
)
{
port
->
opaque
=
opaque
;
port
->
index
=
index
;
port
->
opaque
=
opaque
;
port
->
index
=
index
;
port
->
ops
=
ops
;
port
->
speedmask
=
speedmask
;
usb_port_location
(
port
,
NULL
,
index
+
1
);
}
void
usb_register_port
(
USBBus
*
bus
,
USBPort
*
port
,
void
*
opaque
,
int
index
,
USBPortOps
*
ops
,
int
speedmask
)
{
usb_fill_port
(
port
,
opaque
,
index
,
ops
,
speedmask
);
QTAILQ_INSERT_TAIL
(
&
bus
->
free
,
port
,
next
);
bus
->
nfree
++
;
}
int
usb_register_companion
(
const
char
*
masterbus
,
USBPort
*
ports
[],
uint32_t
portcount
,
uint32_t
firstport
,
void
*
opaque
,
USBPortOps
*
ops
,
int
speedmask
)
{
USBBus
*
bus
;
int
i
;
QTAILQ_FOREACH
(
bus
,
&
busses
,
next
)
{
if
(
strcmp
(
bus
->
qbus
.
name
,
masterbus
)
==
0
)
{
break
;
}
}
if
(
!
bus
||
!
bus
->
ops
->
register_companion
)
{
qerror_report
(
QERR_INVALID_PARAMETER_VALUE
,
"masterbus"
,
"an USB masterbus"
);
if
(
bus
)
{
error_printf_unless_qmp
(
"USB bus '%s' does not allow companion controllers
\n
"
,
masterbus
);
}
return
-
1
;
}
for
(
i
=
0
;
i
<
portcount
;
i
++
)
{
usb_fill_port
(
ports
[
i
],
opaque
,
i
,
ops
,
speedmask
);
}
return
bus
->
ops
->
register_companion
(
bus
,
ports
,
portcount
,
firstport
);
}
void
usb_port_location
(
USBPort
*
downstream
,
USBPort
*
upstream
,
int
portnr
)
{
if
(
upstream
)
{
...
...
hw/usb-ehci.c
浏览文件 @
b4dabf95
...
...
@@ -20,9 +20,6 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* TODO:
* o Downstream port handoff
*/
#include "hw.h"
...
...
@@ -103,10 +100,10 @@
#define PORTSC_BEGIN PORTSC
#define PORTSC_END (PORTSC + 4 * NB_PORTS)
/*
* Bits that are reserve
r
d or are read-only are masked out of values
* Bits that are reserved or are read-only are masked out of values
* written to us by software
*/
#define PORTSC_RO_MASK 0x0070
21c5
#define PORTSC_RO_MASK 0x0070
01c0
#define PORTSC_RWC_MASK 0x0000002a
#define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable
#define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable
...
...
@@ -133,7 +130,7 @@
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
#define NB_PORTS
4
// Number of downstream ports
#define NB_PORTS
6
// Number of downstream ports
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
#define MAX_ITERATIONS 20 // Max number of QH before we break the loop
#define MAX_QH 100 // Max allowable queue heads in a chain
...
...
@@ -373,7 +370,7 @@ struct EHCIState {
qemu_irq
irq
;
target_phys_addr_t
mem_base
;
int
mem
;
int
num_ports
;
int
companion_count
;
/* properties */
uint32_t
freq
;
...
...
@@ -409,6 +406,7 @@ struct EHCIState {
int
astate
;
// Current state in asynchronous schedule
int
pstate
;
// Current state in periodic schedule
USBPort
ports
[
NB_PORTS
];
USBPort
*
companion_ports
[
NB_PORTS
];
uint32_t
usbsts_pending
;
QTAILQ_HEAD
(,
EHCIQueue
)
queues
;
...
...
@@ -731,17 +729,17 @@ static void ehci_attach(USBPort *port)
trace_usb_ehci_port_attach
(
port
->
index
,
port
->
dev
->
product_desc
);
if
(
*
portsc
&
PORTSC_POWNER
)
{
USBPort
*
companion
=
s
->
companion_ports
[
port
->
index
];
companion
->
dev
=
port
->
dev
;
companion
->
ops
->
attach
(
companion
);
return
;
}
*
portsc
|=
PORTSC_CONNECT
;
*
portsc
|=
PORTSC_CSC
;
/*
* If a high speed device is attached then we own this port(indicated
* by zero in the PORTSC_POWNER bit field) so set the status bit
* and set an interrupt if enabled.
*/
if
(
!
(
*
portsc
&
PORTSC_POWNER
))
{
ehci_set_interrupt
(
s
,
USBSTS_PCD
);
}
}
static
void
ehci_detach
(
USBPort
*
port
)
...
...
@@ -751,27 +749,110 @@ static void ehci_detach(USBPort *port)
trace_usb_ehci_port_detach
(
port
->
index
);
*
portsc
&=
~
PORTSC_CONNECT
;
if
(
*
portsc
&
PORTSC_POWNER
)
{
USBPort
*
companion
=
s
->
companion_ports
[
port
->
index
];
companion
->
ops
->
detach
(
companion
);
companion
->
dev
=
NULL
;
return
;
}
ehci_queues_rip_device
(
s
,
port
->
dev
);
*
portsc
&=
~
(
PORTSC_CONNECT
|
PORTSC_PED
);
*
portsc
|=
PORTSC_CSC
;
/*
* If a high speed device is attached then we own this port(indicated
* by zero in the PORTSC_POWNER bit field) so set the status bit
* and set an interrupt if enabled.
*/
if
(
!
(
*
portsc
&
PORTSC_POWNER
))
{
ehci_set_interrupt
(
s
,
USBSTS_PCD
);
}
static
void
ehci_child_detach
(
USBPort
*
port
,
USBDevice
*
child
)
{
EHCIState
*
s
=
port
->
opaque
;
uint32_t
portsc
=
s
->
portsc
[
port
->
index
];
if
(
portsc
&
PORTSC_POWNER
)
{
USBPort
*
companion
=
s
->
companion_ports
[
port
->
index
];
companion
->
ops
->
child_detach
(
companion
,
child
);
companion
->
dev
=
NULL
;
return
;
}
ehci_queues_rip_device
(
s
,
child
);
}
static
void
ehci_wakeup
(
USBPort
*
port
)
{
EHCIState
*
s
=
port
->
opaque
;
uint32_t
portsc
=
s
->
portsc
[
port
->
index
];
if
(
portsc
&
PORTSC_POWNER
)
{
USBPort
*
companion
=
s
->
companion_ports
[
port
->
index
];
if
(
companion
->
ops
->
wakeup
)
{
companion
->
ops
->
wakeup
(
companion
);
}
}
}
static
int
ehci_register_companion
(
USBBus
*
bus
,
USBPort
*
ports
[],
uint32_t
portcount
,
uint32_t
firstport
)
{
EHCIState
*
s
=
container_of
(
bus
,
EHCIState
,
bus
);
uint32_t
i
;
if
(
firstport
+
portcount
>
NB_PORTS
)
{
qerror_report
(
QERR_INVALID_PARAMETER_VALUE
,
"firstport"
,
"firstport on masterbus"
);
error_printf_unless_qmp
(
"firstport value of %u makes companion take ports %u - %u, which "
"is outside of the valid range of 0 - %u
\n
"
,
firstport
,
firstport
,
firstport
+
portcount
-
1
,
NB_PORTS
-
1
);
return
-
1
;
}
for
(
i
=
0
;
i
<
portcount
;
i
++
)
{
if
(
s
->
companion_ports
[
firstport
+
i
])
{
qerror_report
(
QERR_INVALID_PARAMETER_VALUE
,
"masterbus"
,
"an USB masterbus"
);
error_printf_unless_qmp
(
"port %u on masterbus %s already has a companion assigned
\n
"
,
firstport
+
i
,
bus
->
qbus
.
name
);
return
-
1
;
}
}
for
(
i
=
0
;
i
<
portcount
;
i
++
)
{
s
->
companion_ports
[
firstport
+
i
]
=
ports
[
i
];
s
->
ports
[
firstport
+
i
].
speedmask
|=
USB_SPEED_MASK_LOW
|
USB_SPEED_MASK_FULL
;
/* Ensure devs attached before the initial reset go to the companion */
s
->
portsc
[
firstport
+
i
]
=
PORTSC_POWNER
;
}
s
->
companion_count
++
;
s
->
mmio
[
0x05
]
=
(
s
->
companion_count
<<
4
)
|
portcount
;
return
0
;
}
/* 4.1 host controller initialization */
static
void
ehci_reset
(
void
*
opaque
)
{
EHCIState
*
s
=
opaque
;
int
i
;
USBDevice
*
devs
[
NB_PORTS
];
trace_usb_ehci_reset
();
/*
* Do the detach before touching portsc, so that it correctly gets send to
* us or to our companion based on PORTSC_POWNER before the reset.
*/
for
(
i
=
0
;
i
<
NB_PORTS
;
i
++
)
{
devs
[
i
]
=
s
->
ports
[
i
].
dev
;
if
(
devs
[
i
])
{
usb_attach
(
&
s
->
ports
[
i
],
NULL
);
}
}
memset
(
&
s
->
mmio
[
OPREGBASE
],
0x00
,
MMIO_SIZE
-
OPREGBASE
);
s
->
usbcmd
=
NB_MAXINTRATE
<<
USBCMD_ITC_SH
;
...
...
@@ -783,10 +864,13 @@ static void ehci_reset(void *opaque)
s
->
attach_poll_counter
=
0
;
for
(
i
=
0
;
i
<
NB_PORTS
;
i
++
)
{
if
(
s
->
companion_ports
[
i
])
{
s
->
portsc
[
i
]
=
PORTSC_POWNER
|
PORTSC_PPOWER
;
if
(
s
->
ports
[
i
].
dev
)
{
usb_attach
(
&
s
->
ports
[
i
],
s
->
ports
[
i
].
dev
);
}
else
{
s
->
portsc
[
i
]
=
PORTSC_PPOWER
;
}
if
(
devs
[
i
])
{
usb_attach
(
&
s
->
ports
[
i
],
devs
[
i
]);
}
}
ehci_queues_rip_all
(
s
);
...
...
@@ -836,43 +920,67 @@ static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val)
exit
(
1
);
}
static
void
handle_port_owner_write
(
EHCIState
*
s
,
int
port
,
uint32_t
owner
)
{
USBDevice
*
dev
=
s
->
ports
[
port
].
dev
;
uint32_t
*
portsc
=
&
s
->
portsc
[
port
];
uint32_t
orig
;
if
(
s
->
companion_ports
[
port
]
==
NULL
)
return
;
owner
=
owner
&
PORTSC_POWNER
;
orig
=
*
portsc
&
PORTSC_POWNER
;
if
(
!
(
owner
^
orig
))
{
return
;
}
if
(
dev
)
{
usb_attach
(
&
s
->
ports
[
port
],
NULL
);
}
*
portsc
&=
~
PORTSC_POWNER
;
*
portsc
|=
owner
;
if
(
dev
)
{
usb_attach
(
&
s
->
ports
[
port
],
dev
);
}
}
static
void
handle_port_status_write
(
EHCIState
*
s
,
int
port
,
uint32_t
val
)
{
uint32_t
*
portsc
=
&
s
->
portsc
[
port
];
int
rwc
;
USBDevice
*
dev
=
s
->
ports
[
port
].
dev
;
rwc
=
val
&
PORTSC_RWC_MASK
;
/* Clear rwc bits */
*
portsc
&=
~
(
val
&
PORTSC_RWC_MASK
);
/* The guest may clear, but not set the PED bit */
*
portsc
&=
val
|
~
PORTSC_PED
;
/* POWNER is masked out by RO_MASK as it is RO when we've no companion */
handle_port_owner_write
(
s
,
port
,
val
);
/* And finally apply RO_MASK */
val
&=
PORTSC_RO_MASK
;
// handle_read_write_clear(&val, portsc, PORTSC_PEDC | PORTSC_CSC);
*
portsc
&=
~
rwc
;
if
((
val
&
PORTSC_PRESET
)
&&
!
(
*
portsc
&
PORTSC_PRESET
))
{
trace_usb_ehci_port_reset
(
port
,
1
);
}
if
(
!
(
val
&
PORTSC_PRESET
)
&&
(
*
portsc
&
PORTSC_PRESET
))
{
trace_usb_ehci_port_reset
(
port
,
0
);
usb_attach
(
&
s
->
ports
[
port
],
dev
);
// TODO how to handle reset of ports with no device
if
(
dev
)
{
usb_attach
(
&
s
->
ports
[
port
],
dev
);
usb_send_msg
(
dev
,
USB_MSG_RESET
);
}
if
(
s
->
ports
[
port
].
dev
)
{
*
portsc
&=
~
PORTSC_CSC
;
}
/* Table 2.16 Set the enable bit(and enable bit change) to indicate
/*
* Table 2.16 Set the enable bit(and enable bit change) to indicate
* to SW that this port has a high speed device attached
*
* TODO - when to disable?
*/
if
(
dev
&&
(
dev
->
speedmask
&
USB_SPEED_MASK_HIGH
))
{
val
|=
PORTSC_PED
;
val
|=
PORTSC_PEDC
;
}
}
*
portsc
&=
~
PORTSC_RO_MASK
;
...
...
@@ -955,7 +1063,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
val
&=
0x1
;
if
(
val
)
{
for
(
i
=
0
;
i
<
NB_PORTS
;
i
++
)
s
->
portsc
[
i
]
&=
~
PORTSC_POWNER
;
handle_port_owner_write
(
s
,
i
,
0
)
;
}
break
;
...
...
@@ -1111,10 +1219,19 @@ static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw)
return
0
;
}
static
void
ehci_async_complete_packet
(
USB
Device
*
dev
,
USBPacket
*
packet
)
static
void
ehci_async_complete_packet
(
USB
Port
*
port
,
USBPacket
*
packet
)
{
EHCIQueue
*
q
=
container_of
(
packet
,
EHCIQueue
,
packet
);
EHCIQueue
*
q
;
EHCIState
*
s
=
port
->
opaque
;
uint32_t
portsc
=
s
->
portsc
[
port
->
index
];
if
(
portsc
&
PORTSC_POWNER
)
{
USBPort
*
companion
=
s
->
companion_ports
[
port
->
index
];
companion
->
ops
->
complete
(
companion
,
packet
);
return
;
}
q
=
container_of
(
packet
,
EHCIQueue
,
packet
);
trace_usb_ehci_queue_action
(
q
,
"wakeup"
);
assert
(
q
->
async
==
EHCI_ASYNC_INFLIGHT
);
q
->
async
=
EHCI_ASYNC_FINISHED
;
...
...
@@ -1244,8 +1361,6 @@ static int ehci_execute(EHCIQueue *q)
port
=
&
q
->
ehci
->
ports
[
i
];
dev
=
port
->
dev
;
// TODO sometime we will also need to check if we are the port owner
if
(
!
(
q
->
ehci
->
portsc
[
i
]
&
(
PORTSC_CONNECT
)))
{
DPRINTF
(
"Port %d, no exec, not connected(%08X)
\n
"
,
i
,
q
->
ehci
->
portsc
[
i
]);
...
...
@@ -1338,8 +1453,6 @@ static int ehci_process_itd(EHCIState *ehci,
port
=
&
ehci
->
ports
[
j
];
dev
=
port
->
dev
;
// TODO sometime we will also need to check if we are the port owner
if
(
!
(
ehci
->
portsc
[
j
]
&
(
PORTSC_CONNECT
)))
{
continue
;
}
...
...
@@ -2117,38 +2230,48 @@ static void ehci_map(PCIDevice *pci_dev, int region_num,
cpu_register_physical_memory
(
addr
,
size
,
s
->
mem
);
}
static
void
ehci_device_destroy
(
USBBus
*
bus
,
USBDevice
*
dev
)
{
EHCIState
*
s
=
container_of
(
bus
,
EHCIState
,
bus
);
ehci_queues_rip_device
(
s
,
dev
);
}
static
int
usb_ehci_initfn
(
PCIDevice
*
dev
);
static
USBPortOps
ehci_port_ops
=
{
.
attach
=
ehci_attach
,
.
detach
=
ehci_detach
,
.
child_detach
=
ehci_child_detach
,
.
wakeup
=
ehci_wakeup
,
.
complete
=
ehci_async_complete_packet
,
};
static
USBBusOps
ehci_bus_ops
=
{
.
device_destroy
=
ehci_device_destroy
,
.
register_companion
=
ehci_register_companion
,
};
static
PCIDeviceInfo
ehci_info
=
{
static
Property
ehci_properties
[]
=
{
DEFINE_PROP_UINT32
(
"freq"
,
EHCIState
,
freq
,
FRAME_TIMER_FREQ
),
DEFINE_PROP_UINT32
(
"maxframes"
,
EHCIState
,
maxframes
,
128
),
DEFINE_PROP_END_OF_LIST
(),
};
static
PCIDeviceInfo
ehci_info
[]
=
{
{
.
qdev
.
name
=
"usb-ehci"
,
.
qdev
.
size
=
sizeof
(
EHCIState
),
.
init
=
usb_ehci_initfn
,
.
vendor_id
=
PCI_VENDOR_ID_INTEL
,
.
device_id
=
PCI_DEVICE_ID_INTEL_82801D
,
.
device_id
=
PCI_DEVICE_ID_INTEL_82801D
,
/* ich4 */
.
revision
=
0x10
,
.
class_id
=
PCI_CLASS_SERIAL_USB
,
.
qdev
.
props
=
(
Property
[])
{
DEFINE_PROP_UINT32
(
"freq"
,
EHCIState
,
freq
,
FRAME_TIMER_FREQ
),
DEFINE_PROP_UINT32
(
"maxframes"
,
EHCIState
,
maxframes
,
128
),
DEFINE_PROP_END_OF_LIST
(),
},
.
qdev
.
props
=
ehci_properties
,
},{
.
qdev
.
name
=
"ich9-usb-ehci1"
,
.
qdev
.
size
=
sizeof
(
EHCIState
),
.
init
=
usb_ehci_initfn
,
.
vendor_id
=
PCI_VENDOR_ID_INTEL
,
.
device_id
=
PCI_DEVICE_ID_INTEL_82801I_EHCI1
,
.
revision
=
0x03
,
.
class_id
=
PCI_CLASS_SERIAL_USB
,
.
qdev
.
props
=
ehci_properties
,
},{
/* end of list */
}
};
static
int
usb_ehci_initfn
(
PCIDevice
*
dev
)
...
...
@@ -2206,7 +2329,6 @@ static int usb_ehci_initfn(PCIDevice *dev)
for
(
i
=
0
;
i
<
NB_PORTS
;
i
++
)
{
usb_register_port
(
&
s
->
bus
,
&
s
->
ports
[
i
],
s
,
i
,
&
ehci_port_ops
,
USB_SPEED_MASK_HIGH
);
usb_port_location
(
&
s
->
ports
[
i
],
NULL
,
i
+
1
);
s
->
ports
[
i
].
dev
=
0
;
}
...
...
@@ -2228,7 +2350,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
static
void
ehci_register
(
void
)
{
pci_qdev_register
(
&
ehci_info
);
pci_qdev_register
_many
(
ehci_info
);
}
device_init
(
ehci_register
);
...
...
hw/usb-hub.c
浏览文件 @
b4dabf95
...
...
@@ -138,74 +138,6 @@ static const USBDesc desc_hub = {
.
str
=
desc_strings
,
};
static
const
uint8_t
qemu_hub_dev_descriptor
[]
=
{
0x12
,
/* u8 bLength; */
0x01
,
/* u8 bDescriptorType; Device */
0x10
,
0x01
,
/* u16 bcdUSB; v1.1 */
0x09
,
/* u8 bDeviceClass; HUB_CLASSCODE */
0x00
,
/* u8 bDeviceSubClass; */
0x00
,
/* u8 bDeviceProtocol; [ low/full speeds only ] */
0x08
,
/* u8 bMaxPacketSize0; 8 Bytes */
0x00
,
0x00
,
/* u16 idVendor; */
0x00
,
0x00
,
/* u16 idProduct; */
0x01
,
0x01
,
/* u16 bcdDevice */
0x03
,
/* u8 iManufacturer; */
0x02
,
/* u8 iProduct; */
0x01
,
/* u8 iSerialNumber; */
0x01
/* u8 bNumConfigurations; */
};
/* XXX: patch interrupt size */
static
const
uint8_t
qemu_hub_config_descriptor
[]
=
{
/* one configuration */
0x09
,
/* u8 bLength; */
0x02
,
/* u8 bDescriptorType; Configuration */
0x19
,
0x00
,
/* u16 wTotalLength; */
0x01
,
/* u8 bNumInterfaces; (1) */
0x01
,
/* u8 bConfigurationValue; */
0x00
,
/* u8 iConfiguration; */
0xe0
,
/* u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5: Remote wakeup,
4..0: resvd */
0x00
,
/* u8 MaxPower; */
/* USB 1.1:
* USB 2.0, single TT organization (mandatory):
* one interface, protocol 0
*
* USB 2.0, multiple TT organization (optional):
* two interfaces, protocols 1 (like single TT)
* and 2 (multiple TT mode) ... config is
* sometimes settable
* NOT IMPLEMENTED
*/
/* one interface */
0x09
,
/* u8 if_bLength; */
0x04
,
/* u8 if_bDescriptorType; Interface */
0x00
,
/* u8 if_bInterfaceNumber; */
0x00
,
/* u8 if_bAlternateSetting; */
0x01
,
/* u8 if_bNumEndpoints; */
0x09
,
/* u8 if_bInterfaceClass; HUB_CLASSCODE */
0x00
,
/* u8 if_bInterfaceSubClass; */
0x00
,
/* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
0x00
,
/* u8 if_iInterface; */
/* one endpoint (status change endpoint) */
0x07
,
/* u8 ep_bLength; */
0x05
,
/* u8 ep_bDescriptorType; Endpoint */
0x81
,
/* u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03
,
/* u8 ep_bmAttributes; Interrupt */
0x02
,
0x00
,
/* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
0xff
/* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
};
static
const
uint8_t
qemu_hub_hub_descriptor
[]
=
{
0x00
,
/* u8 bLength; patched in later */
...
...
@@ -238,6 +170,9 @@ static void usb_hub_detach(USBPort *port1)
USBHubState
*
s
=
port1
->
opaque
;
USBHubPort
*
port
=
&
s
->
ports
[
port1
->
index
];
/* Let upstream know the device on this port is gone */
s
->
dev
.
port
->
ops
->
child_detach
(
s
->
dev
.
port
,
port1
->
dev
);
port
->
wPortStatus
&=
~
PORT_STAT_CONNECTION
;
port
->
wPortChange
|=
PORT_STAT_C_CONNECTION
;
if
(
port
->
wPortStatus
&
PORT_STAT_ENABLE
)
{
...
...
@@ -246,10 +181,18 @@ static void usb_hub_detach(USBPort *port1)
}
}
static
void
usb_hub_
wakeup
(
USBDevice
*
dev
)
static
void
usb_hub_
child_detach
(
USBPort
*
port1
,
USBDevice
*
child
)
{
USBHubState
*
s
=
dev
->
port
->
opaque
;
USBHubPort
*
port
=
&
s
->
ports
[
dev
->
port
->
index
];
USBHubState
*
s
=
port1
->
opaque
;
/* Pass along upstream */
s
->
dev
.
port
->
ops
->
child_detach
(
s
->
dev
.
port
,
child
);
}
static
void
usb_hub_wakeup
(
USBPort
*
port1
)
{
USBHubState
*
s
=
port1
->
opaque
;
USBHubPort
*
port
=
&
s
->
ports
[
port1
->
index
];
if
(
port
->
wPortStatus
&
PORT_STAT_SUSPEND
)
{
port
->
wPortChange
|=
PORT_STAT_C_SUSPEND
;
...
...
@@ -257,9 +200,9 @@ static void usb_hub_wakeup(USBDevice *dev)
}
}
static
void
usb_hub_complete
(
USB
Device
*
dev
,
USBPacket
*
packet
)
static
void
usb_hub_complete
(
USB
Port
*
port
,
USBPacket
*
packet
)
{
USBHubState
*
s
=
dev
->
port
->
opaque
;
USBHubState
*
s
=
port
->
opaque
;
/*
* Just pass it along upstream for now.
...
...
@@ -537,6 +480,7 @@ static void usb_hub_handle_destroy(USBDevice *dev)
static
USBPortOps
usb_hub_port_ops
=
{
.
attach
=
usb_hub_attach
,
.
detach
=
usb_hub_detach
,
.
child_detach
=
usb_hub_child_detach
,
.
wakeup
=
usb_hub_wakeup
,
.
complete
=
usb_hub_complete
,
};
...
...
hw/usb-musb.c
浏览文件 @
b4dabf95
...
...
@@ -261,17 +261,18 @@
static
void
musb_attach
(
USBPort
*
port
);
static
void
musb_detach
(
USBPort
*
port
);
static
void
musb_schedule_cb
(
USBDevice
*
dev
,
USBPacket
*
p
);
static
void
musb_device_destroy
(
USBBus
*
bus
,
USBDevice
*
dev
);
static
void
musb_child_detach
(
USBPort
*
port
,
USBDevice
*
child
);
static
void
musb_schedule_cb
(
USBPort
*
port
,
USBPacket
*
p
);
static
void
musb_async_cancel_device
(
MUSBState
*
s
,
USBDevice
*
dev
);
static
USBPortOps
musb_port_ops
=
{
.
attach
=
musb_attach
,
.
detach
=
musb_detach
,
.
child_detach
=
musb_child_detach
,
.
complete
=
musb_schedule_cb
,
};
static
USBBusOps
musb_bus_ops
=
{
.
device_destroy
=
musb_device_destroy
,
};
typedef
struct
MUSBPacket
MUSBPacket
;
...
...
@@ -369,7 +370,6 @@ struct MUSBState *musb_init(qemu_irq *irqs)
usb_bus_new
(
&
s
->
bus
,
&
musb_bus_ops
,
NULL
/* FIXME */
);
usb_register_port
(
&
s
->
bus
,
&
s
->
port
,
s
,
0
,
&
musb_port_ops
,
USB_SPEED_MASK_LOW
|
USB_SPEED_MASK_FULL
);
usb_port_location
(
&
s
->
port
,
NULL
,
1
);
return
s
;
}
...
...
@@ -498,10 +498,19 @@ static void musb_detach(USBPort *port)
{
MUSBState
*
s
=
(
MUSBState
*
)
port
->
opaque
;
musb_async_cancel_device
(
s
,
port
->
dev
);
musb_intr_set
(
s
,
musb_irq_disconnect
,
1
);
musb_session_update
(
s
,
1
,
s
->
session
);
}
static
void
musb_child_detach
(
USBPort
*
port
,
USBDevice
*
child
)
{
MUSBState
*
s
=
(
MUSBState
*
)
port
->
opaque
;
musb_async_cancel_device
(
s
,
child
);
}
static
void
musb_cb_tick0
(
void
*
opaque
)
{
MUSBEndPoint
*
ep
=
(
MUSBEndPoint
*
)
opaque
;
...
...
@@ -518,7 +527,7 @@ static void musb_cb_tick1(void *opaque)
#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
static
void
musb_schedule_cb
(
USB
Device
*
dev
,
USBPacket
*
packey
)
static
void
musb_schedule_cb
(
USB
Port
*
port
,
USBPacket
*
packey
)
{
MUSBPacket
*
p
=
container_of
(
packey
,
MUSBPacket
,
p
);
MUSBEndPoint
*
ep
=
p
->
ep
;
...
...
@@ -616,7 +625,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
}
ep
->
status
[
dir
]
=
ret
;
usb_packet_complete
(
s
->
port
.
dev
,
&
ep
->
packey
[
dir
].
p
);
musb_schedule_cb
(
&
s
->
port
,
&
ep
->
packey
[
dir
].
p
);
}
static
void
musb_tx_packet_complete
(
USBPacket
*
packey
,
void
*
opaque
)
...
...
@@ -783,9 +792,8 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
musb_rx_intr_set
(
s
,
epnum
,
1
);
}
static
void
musb_
device_destroy
(
USBBus
*
bu
s
,
USBDevice
*
dev
)
static
void
musb_
async_cancel_device
(
MUSBState
*
s
,
USBDevice
*
dev
)
{
MUSBState
*
s
=
container_of
(
bus
,
MUSBState
,
bus
);
int
ep
,
dir
;
for
(
ep
=
0
;
ep
<
16
;
ep
++
)
{
...
...
hw/usb-ohci.c
浏览文件 @
b4dabf95
...
...
@@ -124,6 +124,7 @@ struct ohci_hcca {
};
static
void
ohci_bus_stop
(
OHCIState
*
ohci
);
static
void
ohci_async_cancel_device
(
OHCIState
*
ohci
,
USBDevice
*
dev
);
/* Bitfields for the first word of an Endpoint Desciptor. */
#define OHCI_ED_FA_SHIFT 0
...
...
@@ -326,6 +327,7 @@ static void ohci_attach(USBPort *port1)
{
OHCIState
*
s
=
port1
->
opaque
;
OHCIPort
*
port
=
&
s
->
rhport
[
port1
->
index
];
uint32_t
old_state
=
port
->
ctrl
;
/* set connect status */
port
->
ctrl
|=
OHCI_PORT_CCS
|
OHCI_PORT_CSC
;
...
...
@@ -343,6 +345,10 @@ static void ohci_attach(USBPort *port1)
}
DPRINTF
(
"usb-ohci: Attached port %d
\n
"
,
port1
->
index
);
if
(
old_state
!=
port
->
ctrl
)
{
ohci_set_interrupt
(
s
,
OHCI_INTR_RHSC
);
}
}
static
void
ohci_detach
(
USBPort
*
port1
)
...
...
@@ -351,6 +357,8 @@ static void ohci_detach(USBPort *port1)
OHCIPort
*
port
=
&
s
->
rhport
[
port1
->
index
];
uint32_t
old_state
=
port
->
ctrl
;
ohci_async_cancel_device
(
s
,
port1
->
dev
);
/* set connect status */
if
(
port
->
ctrl
&
OHCI_PORT_CCS
)
{
port
->
ctrl
&=
~
OHCI_PORT_CCS
;
...
...
@@ -363,19 +371,18 @@ static void ohci_detach(USBPort *port1)
}
DPRINTF
(
"usb-ohci: Detached port %d
\n
"
,
port1
->
index
);
if
(
old_state
!=
port
->
ctrl
)
if
(
old_state
!=
port
->
ctrl
)
{
ohci_set_interrupt
(
s
,
OHCI_INTR_RHSC
);
}
}
static
void
ohci_wakeup
(
USB
Device
*
dev
)
static
void
ohci_wakeup
(
USB
Port
*
port1
)
{
USBBus
*
bus
=
usb_bus_from_device
(
dev
);
OHCIState
*
s
=
container_of
(
bus
,
OHCIState
,
bus
);
int
portnum
=
dev
->
port
->
index
;
OHCIPort
*
port
=
&
s
->
rhport
[
portnum
];
OHCIState
*
s
=
port1
->
opaque
;
OHCIPort
*
port
=
&
s
->
rhport
[
port1
->
index
];
uint32_t
intr
=
0
;
if
(
port
->
ctrl
&
OHCI_PORT_PSS
)
{
DPRINTF
(
"usb-ohci: port %d: wakeup
\n
"
,
port
num
);
DPRINTF
(
"usb-ohci: port %d: wakeup
\n
"
,
port
1
->
index
);
port
->
ctrl
|=
OHCI_PORT_PSSC
;
port
->
ctrl
&=
~
OHCI_PORT_PSS
;
intr
=
OHCI_INTR_RHSC
;
...
...
@@ -394,6 +401,13 @@ static void ohci_wakeup(USBDevice *dev)
ohci_set_interrupt
(
s
,
intr
);
}
static
void
ohci_child_detach
(
USBPort
*
port1
,
USBDevice
*
child
)
{
OHCIState
*
s
=
port1
->
opaque
;
ohci_async_cancel_device
(
s
,
child
);
}
/* Reset the controller */
static
void
ohci_reset
(
void
*
opaque
)
{
...
...
@@ -602,7 +616,7 @@ static void ohci_copy_iso_td(OHCIState *ohci,
static
void
ohci_process_lists
(
OHCIState
*
ohci
,
int
completion
);
static
void
ohci_async_complete_packet
(
USB
Device
*
dev
,
USBPacket
*
packet
)
static
void
ohci_async_complete_packet
(
USB
Port
*
port
,
USBPacket
*
packet
)
{
OHCIState
*
ohci
=
container_of
(
packet
,
OHCIState
,
usb_packet
);
#ifdef DEBUG_PACKET
...
...
@@ -1675,10 +1689,8 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
}
}
static
void
ohci_
device_destroy
(
USBBus
*
bus
,
USBDevice
*
dev
)
static
void
ohci_
async_cancel_device
(
OHCIState
*
ohci
,
USBDevice
*
dev
)
{
OHCIState
*
ohci
=
container_of
(
bus
,
OHCIState
,
bus
);
if
(
ohci
->
async_td
&&
ohci
->
usb_packet
.
owner
==
dev
)
{
usb_cancel_packet
(
&
ohci
->
usb_packet
);
ohci
->
async_td
=
0
;
...
...
@@ -1702,16 +1714,17 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
static
USBPortOps
ohci_port_ops
=
{
.
attach
=
ohci_attach
,
.
detach
=
ohci_detach
,
.
child_detach
=
ohci_child_detach
,
.
wakeup
=
ohci_wakeup
,
.
complete
=
ohci_async_complete_packet
,
};
static
USBBusOps
ohci_bus_ops
=
{
.
device_destroy
=
ohci_device_destroy
,
};
static
void
usb_ohci_init
(
OHCIState
*
ohci
,
DeviceState
*
dev
,
int
num_ports
,
uint32_t
localmem_base
)
static
int
usb_ohci_init
(
OHCIState
*
ohci
,
DeviceState
*
dev
,
int
num_ports
,
uint32_t
localmem_base
,
char
*
masterbus
,
uint32_t
firstport
)
{
int
i
;
...
...
@@ -1731,39 +1744,58 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
usb_frame_time
,
usb_bit_time
);
}
ohci
->
num_ports
=
num_ports
;
if
(
masterbus
)
{
USBPort
*
ports
[
OHCI_MAX_PORTS
];
for
(
i
=
0
;
i
<
num_ports
;
i
++
)
{
ports
[
i
]
=
&
ohci
->
rhport
[
i
].
port
;
}
if
(
usb_register_companion
(
masterbus
,
ports
,
num_ports
,
firstport
,
ohci
,
&
ohci_port_ops
,
USB_SPEED_MASK_LOW
|
USB_SPEED_MASK_FULL
)
!=
0
)
{
return
-
1
;
}
}
else
{
usb_bus_new
(
&
ohci
->
bus
,
&
ohci_bus_ops
,
dev
);
for
(
i
=
0
;
i
<
num_ports
;
i
++
)
{
usb_register_port
(
&
ohci
->
bus
,
&
ohci
->
rhport
[
i
].
port
,
ohci
,
i
,
&
ohci_port_ops
,
USB_SPEED_MASK_LOW
|
USB_SPEED_MASK_FULL
);
}
}
ohci
->
mem
=
cpu_register_io_memory
(
ohci_readfn
,
ohci_writefn
,
ohci
,
DEVICE_LITTLE_ENDIAN
);
ohci
->
localmem_base
=
localmem_base
;
ohci
->
name
=
dev
->
info
->
name
;
usb_bus_new
(
&
ohci
->
bus
,
&
ohci_bus_ops
,
dev
);
ohci
->
num_ports
=
num_ports
;
for
(
i
=
0
;
i
<
num_ports
;
i
++
)
{
usb_register_port
(
&
ohci
->
bus
,
&
ohci
->
rhport
[
i
].
port
,
ohci
,
i
,
&
ohci_port_ops
,
USB_SPEED_MASK_LOW
|
USB_SPEED_MASK_FULL
);
usb_port_location
(
&
ohci
->
rhport
[
i
].
port
,
NULL
,
i
+
1
);
}
ohci
->
async_td
=
0
;
qemu_register_reset
(
ohci_reset
,
ohci
);
return
0
;
}
typedef
struct
{
PCIDevice
pci_dev
;
OHCIState
state
;
char
*
masterbus
;
uint32_t
num_ports
;
uint32_t
firstport
;
}
OHCIPCIState
;
static
int
usb_ohci_initfn_pci
(
struct
PCIDevice
*
dev
)
{
OHCIPCIState
*
ohci
=
DO_UPCAST
(
OHCIPCIState
,
pci_dev
,
dev
);
int
num_ports
=
3
;
ohci
->
pci_dev
.
config
[
PCI_CLASS_PROG
]
=
0x10
;
/* OHCI */
/* TODO: RST# value should be 0. */
ohci
->
pci_dev
.
config
[
PCI_INTERRUPT_PIN
]
=
0x01
;
/* interrupt pin 1 */
usb_ohci_init
(
&
ohci
->
state
,
&
dev
->
qdev
,
num_ports
,
0
);
if
(
usb_ohci_init
(
&
ohci
->
state
,
&
dev
->
qdev
,
ohci
->
num_ports
,
0
,
ohci
->
masterbus
,
ohci
->
firstport
)
!=
0
)
{
return
-
1
;
}
ohci
->
state
.
irq
=
ohci
->
pci_dev
.
irq
[
0
];
/* TODO: avoid cast below by using dev */
...
...
@@ -1787,7 +1819,8 @@ static int ohci_init_pxa(SysBusDevice *dev)
{
OHCISysBusState
*
s
=
FROM_SYSBUS
(
OHCISysBusState
,
dev
);
usb_ohci_init
(
&
s
->
ohci
,
&
dev
->
qdev
,
s
->
num_ports
,
s
->
dma_offset
);
/* Cannot fail as we pass NULL for masterbus */
usb_ohci_init
(
&
s
->
ohci
,
&
dev
->
qdev
,
s
->
num_ports
,
s
->
dma_offset
,
NULL
,
0
);
sysbus_init_irq
(
dev
,
&
s
->
ohci
.
irq
);
sysbus_init_mmio
(
dev
,
0x1000
,
s
->
ohci
.
mem
);
...
...
@@ -1802,6 +1835,12 @@ static PCIDeviceInfo ohci_pci_info = {
.
vendor_id
=
PCI_VENDOR_ID_APPLE
,
.
device_id
=
PCI_DEVICE_ID_APPLE_IPID_USB
,
.
class_id
=
PCI_CLASS_SERIAL_USB
,
.
qdev
.
props
=
(
Property
[])
{
DEFINE_PROP_STRING
(
"masterbus"
,
OHCIPCIState
,
masterbus
),
DEFINE_PROP_UINT32
(
"num-ports"
,
OHCIPCIState
,
num_ports
,
3
),
DEFINE_PROP_UINT32
(
"firstport"
,
OHCIPCIState
,
firstport
,
0
),
DEFINE_PROP_END_OF_LIST
(),
},
};
static
SysBusDeviceInfo
ohci_sysbus_info
=
{
...
...
hw/usb-uhci.c
浏览文件 @
b4dabf95
...
...
@@ -132,7 +132,7 @@ typedef struct UHCIPort {
struct
UHCIState
{
PCIDevice
dev
;
USBBus
bus
;
USBBus
bus
;
/* Note unused when we're a companion controller */
uint16_t
cmd
;
/* cmd register */
uint16_t
status
;
uint16_t
intr
;
/* interrupt enable register */
...
...
@@ -150,6 +150,10 @@ struct UHCIState {
/* Active packets */
QTAILQ_HEAD
(,
UHCIAsync
)
async_pending
;
uint8_t
num_ports_vmstate
;
/* Properties */
char
*
masterbus
;
uint32_t
firstport
;
};
typedef
struct
UHCI_TD
{
...
...
@@ -606,6 +610,8 @@ static void uhci_detach(USBPort *port1)
UHCIState
*
s
=
port1
->
opaque
;
UHCIPort
*
port
=
&
s
->
ports
[
port1
->
index
];
uhci_async_cancel_device
(
s
,
port1
->
dev
);
/* set connect status */
if
(
port
->
ctrl
&
UHCI_PORT_CCS
)
{
port
->
ctrl
&=
~
UHCI_PORT_CCS
;
...
...
@@ -620,11 +626,17 @@ static void uhci_detach(USBPort *port1)
uhci_resume
(
s
);
}
static
void
uhci_wakeup
(
USBDevice
*
dev
)
static
void
uhci_child_detach
(
USBPort
*
port1
,
USBDevice
*
child
)
{
UHCIState
*
s
=
port1
->
opaque
;
uhci_async_cancel_device
(
s
,
child
);
}
static
void
uhci_wakeup
(
USBPort
*
port1
)
{
USBBus
*
bus
=
usb_bus_from_device
(
dev
);
UHCIState
*
s
=
container_of
(
bus
,
UHCIState
,
bus
);
UHCIPort
*
port
=
s
->
ports
+
dev
->
port
->
index
;
UHCIState
*
s
=
port1
->
opaque
;
UHCIPort
*
port
=
&
s
->
ports
[
port1
->
index
];
if
(
port
->
ctrl
&
UHCI_PORT_SUSPEND
&&
!
(
port
->
ctrl
&
UHCI_PORT_RD
))
{
port
->
ctrl
|=
UHCI_PORT_RD
;
...
...
@@ -657,7 +669,7 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
return
ret
;
}
static
void
uhci_async_complete
(
USB
Device
*
dev
,
USBPacket
*
packet
);
static
void
uhci_async_complete
(
USB
Port
*
port
,
USBPacket
*
packet
);
static
void
uhci_process_frame
(
UHCIState
*
s
);
/* return -1 if fatal error (frame must be stopped)
...
...
@@ -849,7 +861,7 @@ done:
return
len
;
}
static
void
uhci_async_complete
(
USB
Device
*
dev
,
USBPacket
*
packet
)
static
void
uhci_async_complete
(
USB
Port
*
port
,
USBPacket
*
packet
)
{
UHCIAsync
*
async
=
container_of
(
packet
,
UHCIAsync
,
packet
);
UHCIState
*
s
=
async
->
uhci
;
...
...
@@ -1096,22 +1108,15 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
register_ioport_read
(
addr
,
32
,
1
,
uhci_ioport_readb
,
s
);
}
static
void
uhci_device_destroy
(
USBBus
*
bus
,
USBDevice
*
dev
)
{
UHCIState
*
s
=
container_of
(
bus
,
UHCIState
,
bus
);
uhci_async_cancel_device
(
s
,
dev
);
}
static
USBPortOps
uhci_port_ops
=
{
.
attach
=
uhci_attach
,
.
detach
=
uhci_detach
,
.
child_detach
=
uhci_child_detach
,
.
wakeup
=
uhci_wakeup
,
.
complete
=
uhci_async_complete
,
};
static
USBBusOps
uhci_bus_ops
=
{
.
device_destroy
=
uhci_device_destroy
,
};
static
int
usb_uhci_common_initfn
(
PCIDevice
*
dev
)
...
...
@@ -1125,11 +1130,22 @@ static int usb_uhci_common_initfn(PCIDevice *dev)
pci_conf
[
PCI_INTERRUPT_PIN
]
=
4
;
// interrupt pin 3
pci_conf
[
USB_SBRN
]
=
USB_RELEASE_1
;
// release number
usb_bus_new
(
&
s
->
bus
,
&
uhci_bus_ops
,
&
s
->
dev
.
qdev
);
if
(
s
->
masterbus
)
{
USBPort
*
ports
[
NB_PORTS
];
for
(
i
=
0
;
i
<
NB_PORTS
;
i
++
)
{
ports
[
i
]
=
&
s
->
ports
[
i
].
port
;
}
if
(
usb_register_companion
(
s
->
masterbus
,
ports
,
NB_PORTS
,
s
->
firstport
,
s
,
&
uhci_port_ops
,
USB_SPEED_MASK_LOW
|
USB_SPEED_MASK_FULL
)
!=
0
)
{
return
-
1
;
}
}
else
{
usb_bus_new
(
&
s
->
bus
,
&
uhci_bus_ops
,
&
s
->
dev
.
qdev
);
for
(
i
=
0
;
i
<
NB_PORTS
;
i
++
)
{
usb_register_port
(
&
s
->
bus
,
&
s
->
ports
[
i
].
port
,
s
,
i
,
&
uhci_port_ops
,
USB_SPEED_MASK_LOW
|
USB_SPEED_MASK_FULL
);
usb_port_location
(
&
s
->
ports
[
i
].
port
,
NULL
,
i
+
1
);
}
}
s
->
frame_timer
=
qemu_new_timer_ns
(
vm_clock
,
uhci_frame_timer
,
s
);
s
->
num_ports_vmstate
=
NB_PORTS
;
...
...
@@ -1160,6 +1176,12 @@ static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
return
usb_uhci_common_initfn
(
dev
);
}
static
Property
uhci_properties
[]
=
{
DEFINE_PROP_STRING
(
"masterbus"
,
UHCIState
,
masterbus
),
DEFINE_PROP_UINT32
(
"firstport"
,
UHCIState
,
firstport
,
0
),
DEFINE_PROP_END_OF_LIST
(),
};
static
PCIDeviceInfo
uhci_info
[]
=
{
{
.
qdev
.
name
=
"piix3-usb-uhci"
,
...
...
@@ -1170,6 +1192,7 @@ static PCIDeviceInfo uhci_info[] = {
.
device_id
=
PCI_DEVICE_ID_INTEL_82371SB_2
,
.
revision
=
0x01
,
.
class_id
=
PCI_CLASS_SERIAL_USB
,
.
qdev
.
props
=
uhci_properties
,
},{
.
qdev
.
name
=
"piix4-usb-uhci"
,
.
qdev
.
size
=
sizeof
(
UHCIState
),
...
...
@@ -1179,6 +1202,7 @@ static PCIDeviceInfo uhci_info[] = {
.
device_id
=
PCI_DEVICE_ID_INTEL_82371AB_2
,
.
revision
=
0x01
,
.
class_id
=
PCI_CLASS_SERIAL_USB
,
.
qdev
.
props
=
uhci_properties
,
},{
.
qdev
.
name
=
"vt82c686b-usb-uhci"
,
.
qdev
.
size
=
sizeof
(
UHCIState
),
...
...
@@ -1188,6 +1212,37 @@ static PCIDeviceInfo uhci_info[] = {
.
device_id
=
PCI_DEVICE_ID_VIA_UHCI
,
.
revision
=
0x01
,
.
class_id
=
PCI_CLASS_SERIAL_USB
,
.
qdev
.
props
=
uhci_properties
,
},{
.
qdev
.
name
=
"ich9-usb-uhci1"
,
.
qdev
.
size
=
sizeof
(
UHCIState
),
.
qdev
.
vmsd
=
&
vmstate_uhci
,
.
init
=
usb_uhci_common_initfn
,
.
vendor_id
=
PCI_VENDOR_ID_INTEL
,
.
device_id
=
PCI_DEVICE_ID_INTEL_82801I_UHCI1
,
.
revision
=
0x03
,
.
class_id
=
PCI_CLASS_SERIAL_USB
,
.
qdev
.
props
=
uhci_properties
,
},{
.
qdev
.
name
=
"ich9-usb-uhci2"
,
.
qdev
.
size
=
sizeof
(
UHCIState
),
.
qdev
.
vmsd
=
&
vmstate_uhci
,
.
init
=
usb_uhci_common_initfn
,
.
vendor_id
=
PCI_VENDOR_ID_INTEL
,
.
device_id
=
PCI_DEVICE_ID_INTEL_82801I_UHCI2
,
.
revision
=
0x03
,
.
class_id
=
PCI_CLASS_SERIAL_USB
,
.
qdev
.
props
=
uhci_properties
,
},{
.
qdev
.
name
=
"ich9-usb-uhci3"
,
.
qdev
.
size
=
sizeof
(
UHCIState
),
.
qdev
.
vmsd
=
&
vmstate_uhci
,
.
init
=
usb_uhci_common_initfn
,
.
vendor_id
=
PCI_VENDOR_ID_INTEL
,
.
device_id
=
PCI_DEVICE_ID_INTEL_82801I_UHCI3
,
.
revision
=
0x03
,
.
class_id
=
PCI_CLASS_SERIAL_USB
,
.
qdev
.
props
=
uhci_properties
,
},{
/* end of list */
}
...
...
hw/usb.c
浏览文件 @
b4dabf95
...
...
@@ -40,19 +40,18 @@ void usb_attach(USBPort *port, USBDevice *dev)
}
else
{
/* detach */
dev
=
port
->
dev
;
assert
(
dev
);
port
->
ops
->
detach
(
port
);
if
(
dev
)
{
usb_send_msg
(
dev
,
USB_MSG_DETACH
);
dev
->
port
=
NULL
;
port
->
dev
=
NULL
;
}
}
}
void
usb_wakeup
(
USBDevice
*
dev
)
{
if
(
dev
->
remote_wakeup
&&
dev
->
port
&&
dev
->
port
->
ops
->
wakeup
)
{
dev
->
port
->
ops
->
wakeup
(
dev
);
dev
->
port
->
ops
->
wakeup
(
dev
->
port
);
}
}
...
...
@@ -335,7 +334,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
/* Note: p->owner != dev is possible in case dev is a hub */
assert
(
p
->
owner
!=
NULL
);
dev
->
port
->
ops
->
complete
(
dev
,
p
);
dev
->
port
->
ops
->
complete
(
dev
->
port
,
p
);
p
->
owner
=
NULL
;
}
...
...
hw/usb.h
浏览文件 @
b4dabf95
...
...
@@ -252,8 +252,18 @@ struct USBDeviceInfo {
typedef
struct
USBPortOps
{
void
(
*
attach
)(
USBPort
*
port
);
void
(
*
detach
)(
USBPort
*
port
);
void
(
*
wakeup
)(
USBDevice
*
dev
);
void
(
*
complete
)(
USBDevice
*
dev
,
USBPacket
*
p
);
/*
* This gets called when a device downstream from the device attached to
* the port (iow attached through a hub) gets detached.
*/
void
(
*
child_detach
)(
USBPort
*
port
,
USBDevice
*
child
);
void
(
*
wakeup
)(
USBPort
*
port
);
/*
* Note that port->dev will be different then the device from which
* the packet originated when a hub is involved, if you want the orginating
* device use p->owner
*/
void
(
*
complete
)(
USBPort
*
port
,
USBPacket
*
p
);
}
USBPortOps
;
/* USB port on which a device can be connected */
...
...
@@ -344,7 +354,8 @@ struct USBBus {
};
struct
USBBusOps
{
void
(
*
device_destroy
)(
USBBus
*
bus
,
USBDevice
*
dev
);
int
(
*
register_companion
)(
USBBus
*
bus
,
USBPort
*
ports
[],
uint32_t
portcount
,
uint32_t
firstport
);
};
void
usb_bus_new
(
USBBus
*
bus
,
USBBusOps
*
ops
,
DeviceState
*
host
);
...
...
@@ -356,6 +367,9 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name);
USBDevice
*
usbdevice_create
(
const
char
*
cmdline
);
void
usb_register_port
(
USBBus
*
bus
,
USBPort
*
port
,
void
*
opaque
,
int
index
,
USBPortOps
*
ops
,
int
speedmask
);
int
usb_register_companion
(
const
char
*
masterbus
,
USBPort
*
ports
[],
uint32_t
portcount
,
uint32_t
firstport
,
void
*
opaque
,
USBPortOps
*
ops
,
int
speedmask
);
void
usb_port_location
(
USBPort
*
downstream
,
USBPort
*
upstream
,
int
portnr
);
void
usb_unregister_port
(
USBBus
*
bus
,
USBPort
*
port
);
int
usb_device_attach
(
USBDevice
*
dev
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录