1 /*
2  *  Copyright (C) 2004-2009  Anders Gavare.  All rights reserved.
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions are met:
6  *
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. The name of the author may not be used to endorse or promote products
13  *     derived from this software without specific prior written permission.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  *  SUCH DAMAGE.
26  *
27  *
28  *  COMMENT: USB Open Host Controller Interface
29  *
30  *  TODO
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "cpu.h"
38 #include "device.h"
39 #include "interrupt.h"
40 #include "machine.h"
41 #include "memory.h"
42 #include "misc.h"
43 
44 #include "thirdparty/ohcireg.h"
45 
46 
47 /*  Length is 0x1000 at least on Playstation 2  */
48 #define	DEV_OHCI_LENGTH		0x1000
49 
50 
51 #define debug fatal
52 
53 
54 struct ohci_data {
55 	struct interrupt	irq;
56 
57 	int			port1reset;
58 };
59 
60 
DEVICE_ACCESS(ohci)61 DEVICE_ACCESS(ohci)
62 {
63 	struct ohci_data *d = (struct ohci_data *) extra;
64 	uint64_t idata = 0, odata = 0;
65 	const char *name = NULL;
66 
67 	if (writeflag == MEM_WRITE)
68 		idata = memory_readmax64(cpu, data, len);
69 
70 	switch (relative_addr) {
71 	case OHCI_REVISION:
72 		name = "REVISION";
73 		if (writeflag == MEM_READ) {
74 			odata = 0x10;	/*  Version 1.0.  */
75 		}
76 		break;
77 	case OHCI_COMMAND_STATUS:
78 		name = "COMMAND_STATUS";
79 		if (idata == 0x2) {
80 			fatal("Hm... OHCI COMMAND STATUS\n");
81 			INTERRUPT_ASSERT(d->irq);
82 		}
83 		break;
84 	case OHCI_INTERRUPT_STATUS:
85 		name = "INTERRUPT_STATUS";
86 		odata = OHCI_WDH;
87 		break;
88 /*
89  *  TODO: It now sleeps at      tsleep(xfer, PRIBIO, "usbsyn", 0);
90  *  in netbsd/src/sys/dev/usb/usbdi.c
91  */
92 	case OHCI_RH_DESCRIPTOR_A:
93 		name = "RH_DESCRIPTOR_A";
94 		odata = 2;	/*  Nr of ports  */
95 		break;
96 	case OHCI_RH_STATUS:
97 		name = "RH_STATUS";
98 		/*  TODO  */
99 		break;
100 	case OHCI_RH_PORT_STATUS(1):	/*  First port  */
101 		name = "RH_PORT_STATUS(1)";
102 		if (writeflag == MEM_READ) {
103 			/*  Status = low 16, Change = top 16  */
104 			odata = 0x10101;
105 			/*  0x0001 = connected
106 			    0x0100 = power  */
107 			if (d->port1reset)
108 				odata |= (0x10 << 16) | 0x10;
109 		} else {
110 			/*  0x10 = UPS_C_PORT_RESET  */
111 			if (idata & 0x10)
112 				d->port1reset = 1;
113 			if (idata & 0x100000)
114 				d->port1reset = 0;
115 		}
116 		break;
117 	case OHCI_RH_PORT_STATUS(2):	/*  Second port  */
118 		name = "RH_PORT_STATUS(2)";
119 		/*  TODO  */
120 		odata = 0;
121 		break;
122 	default:
123 		if (writeflag == MEM_READ) {
124 			debug("[ ohci: read from addr 0x%x: 0x%llx ]\n",
125 			    (int)relative_addr, (long long)odata);
126 		} else {
127 			debug("[ ohci: write to addr 0x%x: 0x%llx ]\n",
128 			    (int)relative_addr, (long long)idata);
129 		}
130 	}
131 
132 	if (name != NULL) {
133 		if (writeflag == MEM_READ)
134 			debug("[ ohci: read from %s: 0x%llx ]\n",
135 			    name, (long long)odata);
136 		else
137 			debug("[ ohci: write to %s: 0x%llx ]\n",
138 			    name, (long long)idata);
139 	}
140 
141 	if (writeflag == MEM_READ)
142 		memory_writemax64(cpu, data, len, odata);
143 
144 	return 1;
145 }
146 
147 
DEVINIT(ohci)148 DEVINIT(ohci)
149 {
150 	struct ohci_data *d;
151 
152 	CHECK_ALLOCATION(d = (struct ohci_data *) malloc(sizeof(struct ohci_data)));
153 	memset(d, 0, sizeof(struct ohci_data));
154 
155 	INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
156 
157 	memory_device_register(devinit->machine->memory,
158 	    devinit->name, devinit->addr,
159 	    DEV_OHCI_LENGTH, dev_ohci_access, d, DM_DEFAULT, NULL);
160 
161 	return 1;
162 }
163 
164