aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>2009-04-19 09:15:50 +0000
committeraurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>2009-04-19 09:15:50 +0000
commitac611340c9e21f3f9f1247a23de08d8764174b83 (patch)
tree56b2f16eefbd8fbb3f8f8fc1df468458291313ff /hw/usb-ohci.c
parentlinux-user: Linux kernel's fchmodat and faccessat have three args (no 4th arg) (diff)
downloadqemu-kvm-ac611340c9e21f3f9f1247a23de08d8764174b83.tar.gz
qemu-kvm-ac611340c9e21f3f9f1247a23de08d8764174b83.tar.bz2
qemu-kvm-ac611340c9e21f3f9f1247a23de08d8764174b83.zip
Adds SM501 usb host emulation feature.
It makes usb keyboard available for sh4/r2d system emulation. The changes for "hw/usb-ohci.c" are as follows. - 'localmem_base' is introduced as OHCIState struct member. SM501 has a local memory, and it is used to pass and receive data with OHCI driver. OHCI driver accesses it with SH4 physical memory address, and SM501 accesses it with SM501 local address. 'localmem_base' holds where the SM501 local memory is mapped into SH4 physical address space. - Memory access functions modified to adjust address with 'localmem_base'. The functions are, ohci_read_*(), ohci_put_*(), and ohci_copy_*(). - ohci_read_hcca() and ohci_put_hcca() are introduced for more consistent implementation. For other source files, it does, - introduces usb_ohci_init_sm501(). - adds irq argument for SM501 initialization, to emulate USB interrupts. Signed-off-by: Shin-ichiro KAWASAKI <kawasaki@juno.dti.ne.jp> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7188 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/usb-ohci.c')
-rw-r--r--hw/usb-ohci.c137
1 files changed, 96 insertions, 41 deletions
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index e59bc8a46..09944d0dc 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -32,6 +32,7 @@
#include "usb.h"
#include "pci.h"
#include "pxa.h"
+#include "devices.h"
//#define DEBUG_OHCI
/* Dump packet contents. */
@@ -60,7 +61,8 @@ typedef struct OHCIPort {
enum ohci_type {
OHCI_TYPE_PCI,
- OHCI_TYPE_PXA
+ OHCI_TYPE_PXA,
+ OHCI_TYPE_SM501,
};
typedef struct {
@@ -108,6 +110,9 @@ typedef struct {
uint32_t hreset;
uint32_t htest;
+ /* SM501 local memory offset */
+ target_phys_addr_t localmem_base;
+
/* Active packets. */
uint32_t old_ctl;
USBPacket usb_packet;
@@ -425,10 +430,13 @@ static void ohci_reset(void *opaque)
}
/* Get an array of dwords from main memory */
-static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
+static inline int get_dwords(OHCIState *ohci,
+ uint32_t addr, uint32_t *buf, int num)
{
int i;
+ addr += ohci->localmem_base;
+
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
*buf = le32_to_cpu(*buf);
@@ -438,10 +446,13 @@ static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
}
/* Put an array of dwords in to main memory */
-static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
+static inline int put_dwords(OHCIState *ohci,
+ uint32_t addr, uint32_t *buf, int num)
{
int i;
+ addr += ohci->localmem_base;
+
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint32_t tmp = cpu_to_le32(*buf);
cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
@@ -451,10 +462,13 @@ static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
}
/* Get an array of words from main memory */
-static inline int get_words(uint32_t addr, uint16_t *buf, int num)
+static inline int get_words(OHCIState *ohci,
+ uint32_t addr, uint16_t *buf, int num)
{
int i;
+ addr += ohci->localmem_base;
+
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
*buf = le16_to_cpu(*buf);
@@ -464,10 +478,13 @@ static inline int get_words(uint32_t addr, uint16_t *buf, int num)
}
/* Put an array of words in to main memory */
-static inline int put_words(uint32_t addr, uint16_t *buf, int num)
+static inline int put_words(OHCIState *ohci,
+ uint32_t addr, uint16_t *buf, int num)
{
int i;
+ addr += ohci->localmem_base;
+
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint16_t tmp = cpu_to_le16(*buf);
cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
@@ -476,40 +493,63 @@ static inline int put_words(uint32_t addr, uint16_t *buf, int num)
return 1;
}
-static inline int ohci_read_ed(uint32_t addr, struct ohci_ed *ed)
+static inline int ohci_read_ed(OHCIState *ohci,
+ uint32_t addr, struct ohci_ed *ed)
{
- return get_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+ return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
}
-static inline int ohci_read_td(uint32_t addr, struct ohci_td *td)
+static inline int ohci_read_td(OHCIState *ohci,
+ uint32_t addr, struct ohci_td *td)
{
- return get_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2);
+ return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
}
-static inline int ohci_read_iso_td(uint32_t addr, struct ohci_iso_td *td)
+static inline int ohci_read_iso_td(OHCIState *ohci,
+ uint32_t addr, struct ohci_iso_td *td)
{
- return (get_dwords(addr, (uint32_t *)td, 4) &&
- get_words(addr + 16, td->offset, 8));
+ return (get_dwords(ohci, addr, (uint32_t *)td, 4) &&
+ get_words(ohci, addr + 16, td->offset, 8));
}
-static inline int ohci_put_ed(uint32_t addr, struct ohci_ed *ed)
+static inline int ohci_read_hcca(OHCIState *ohci,
+ uint32_t addr, struct ohci_hcca *hcca)
{
- return put_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+ cpu_physical_memory_rw(addr + ohci->localmem_base,
+ (uint8_t *)hcca, sizeof(*hcca), 0);
+ return 1;
}
-static inline int ohci_put_td(uint32_t addr, struct ohci_td *td)
+static inline int ohci_put_ed(OHCIState *ohci,
+ uint32_t addr, struct ohci_ed *ed)
{
- return put_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2);
+ return put_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
}
-static inline int ohci_put_iso_td(uint32_t addr, struct ohci_iso_td *td)
+static inline int ohci_put_td(OHCIState *ohci,
+ uint32_t addr, struct ohci_td *td)
{
- return (put_dwords(addr, (uint32_t *)td, 4) &&
- put_words(addr + 16, td->offset, 8));
+ return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
+}
+
+static inline int ohci_put_iso_td(OHCIState *ohci,
+ uint32_t addr, struct ohci_iso_td *td)
+{
+ return (put_dwords(ohci, addr, (uint32_t *)td, 4) &&
+ put_words(ohci, addr + 16, td->offset, 8));
+}
+
+static inline int ohci_put_hcca(OHCIState *ohci,
+ uint32_t addr, struct ohci_hcca *hcca)
+{
+ cpu_physical_memory_rw(addr + ohci->localmem_base,
+ (uint8_t *)hcca, sizeof(*hcca), 1);
+ return 1;
}
/* Read/Write the contents of a TD from/to main memory. */
-static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write)
+static void ohci_copy_td(OHCIState *ohci, struct ohci_td *td,
+ uint8_t *buf, int len, int write)
{
uint32_t ptr;
uint32_t n;
@@ -518,16 +558,17 @@ static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write)
n = 0x1000 - (ptr & 0xfff);
if (n > len)
n = len;
- cpu_physical_memory_rw(ptr, buf, n, write);
+ cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, n, write);
if (n == len)
return;
ptr = td->be & ~0xfffu;
buf += n;
- cpu_physical_memory_rw(ptr, buf, len - n, write);
+ cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, len - n, write);
}
/* Read/Write the contents of an ISO TD from/to main memory. */
-static void ohci_copy_iso_td(uint32_t start_addr, uint32_t end_addr,
+static void ohci_copy_iso_td(OHCIState *ohci,
+ uint32_t start_addr, uint32_t end_addr,
uint8_t *buf, int len, int write)
{
uint32_t ptr;
@@ -537,12 +578,12 @@ static void ohci_copy_iso_td(uint32_t start_addr, uint32_t end_addr,
n = 0x1000 - (ptr & 0xfff);
if (n > len)
n = len;
- cpu_physical_memory_rw(ptr, buf, n, write);
+ cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, n, write);
if (n == len)
return;
ptr = end_addr & ~0xfffu;
buf += n;
- cpu_physical_memory_rw(ptr, buf, len - n, write);
+ cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, len - n, write);
}
static void ohci_process_lists(OHCIState *ohci, int completion);
@@ -579,7 +620,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
addr = ed->head & OHCI_DPTR_MASK;
- if (!ohci_read_iso_td(addr, &iso_td)) {
+ if (!ohci_read_iso_td(ohci, addr, &iso_td)) {
printf("usb-ohci: ISO_TD read error at %x\n", addr);
return 0;
}
@@ -621,7 +662,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
i = OHCI_BM(iso_td.flags, TD_DI);
if (i < ohci->done_count)
ohci->done_count = i;
- ohci_put_iso_td(addr, &iso_td);
+ ohci_put_iso_td(ohci, addr, &iso_td);
return 0;
}
@@ -696,7 +737,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
}
if (len && dir != OHCI_TD_DIR_IN) {
- ohci_copy_iso_td(start_addr, end_addr, ohci->usb_buf, len, 0);
+ ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 0);
}
if (completion) {
@@ -732,7 +773,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
/* Writeback */
if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
/* IN transfer succeeded */
- ohci_copy_iso_td(start_addr, end_addr, ohci->usb_buf, ret, 1);
+ ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 1);
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
OHCI_CC_NOERROR);
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);
@@ -788,7 +829,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
if (i < ohci->done_count)
ohci->done_count = i;
}
- ohci_put_iso_td(addr, &iso_td);
+ ohci_put_iso_td(ohci, addr, &iso_td);
return 1;
}
@@ -818,7 +859,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
#endif
return 1;
}
- if (!ohci_read_td(addr, &td)) {
+ if (!ohci_read_td(ohci, addr, &td)) {
fprintf(stderr, "usb-ohci: TD read error at %x\n", addr);
return 0;
}
@@ -859,7 +900,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
if (len && dir != OHCI_TD_DIR_IN && !completion) {
- ohci_copy_td(&td, ohci->usb_buf, len, 0);
+ ohci_copy_td(ohci, &td, ohci->usb_buf, len, 0);
}
}
@@ -918,7 +959,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
if (ret >= 0) {
if (dir == OHCI_TD_DIR_IN) {
- ohci_copy_td(&td, ohci->usb_buf, ret, 1);
+ ohci_copy_td(ohci, &td, ohci->usb_buf, ret, 1);
#ifdef DEBUG_PACKET
dprintf(" data:");
for (i = 0; i < ret; i++)
@@ -987,7 +1028,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
i = OHCI_BM(td.flags, TD_DI);
if (i < ohci->done_count)
ohci->done_count = i;
- ohci_put_td(addr, &td);
+ ohci_put_td(ohci, addr, &td);
return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
}
@@ -1005,7 +1046,7 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
return 0;
for (cur = head; cur; cur = next_ed) {
- if (!ohci_read_ed(cur, &ed)) {
+ if (!ohci_read_ed(ohci, cur, &ed)) {
fprintf(stderr, "usb-ohci: ED read error at %x\n", cur);
return 0;
}
@@ -1046,7 +1087,7 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
}
}
- ohci_put_ed(cur, &ed);
+ ohci_put_ed(ohci, cur, &ed);
}
return active;
@@ -1087,7 +1128,7 @@ static void ohci_frame_boundary(void *opaque)
OHCIState *ohci = opaque;
struct ohci_hcca hcca;
- cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 0);
+ ohci_read_hcca(ohci, ohci->hcca, &hcca);
/* Process all the lists at the end of the frame */
if (ohci->ctl & OHCI_CTL_PLE) {
@@ -1131,7 +1172,7 @@ static void ohci_frame_boundary(void *opaque)
ohci_sof(ohci);
/* Writeback HCCA */
- cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 1);
+ ohci_put_hcca(ohci, ohci->hcca, &hcca);
}
/* Start sending SOF tokens across the USB bus, lists are processed in
@@ -1620,7 +1661,8 @@ static CPUWriteMemoryFunc *ohci_writefn[3]={
};
static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
- qemu_irq irq, enum ohci_type type, const char *name)
+ qemu_irq irq, enum ohci_type type,
+ const char *name, uint32_t localmem_base)
{
int i;
@@ -1641,6 +1683,7 @@ static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
}
ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci);
+ ohci->localmem_base = localmem_base;
ohci->name = name;
ohci->irq = irq;
@@ -1687,7 +1730,7 @@ void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn)
ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0],
- OHCI_TYPE_PCI, ohci->pci_dev.name);
+ OHCI_TYPE_PCI, ohci->pci_dev.name, 0);
pci_register_io_region((struct PCIDevice *)ohci, 0, 256,
PCI_ADDRESS_SPACE_MEM, ohci_mapfunc);
@@ -1699,7 +1742,19 @@ void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
usb_ohci_init(ohci, num_ports, devfn, irq,
- OHCI_TYPE_PXA, "OHCI USB");
+ OHCI_TYPE_PXA, "OHCI USB", 0);
cpu_register_physical_memory(base, 0x1000, ohci->mem);
}
+
+void usb_ohci_init_sm501(uint32_t mmio_base, uint32_t localmem_base,
+ int num_ports, int devfn, qemu_irq irq)
+{
+ OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
+
+ usb_ohci_init(ohci, num_ports, devfn, irq,
+ OHCI_TYPE_SM501, "OHCI USB", localmem_base);
+
+ cpu_register_physical_memory(mmio_base, 0x1000, ohci->mem);
+}
+