Commit 0d92ed3022694aa6ec9172938e999871fa04f711
1 parent
6650ee6d
OHCI USB host emulation.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1928 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
11 changed files
with
1306 additions
and
84 deletions
Makefile.target
@@ -307,7 +307,7 @@ SOUND_HW += fmopl.o adlib.o | @@ -307,7 +307,7 @@ SOUND_HW += fmopl.o adlib.o | ||
307 | endif | 307 | endif |
308 | 308 | ||
309 | # USB layer | 309 | # USB layer |
310 | -VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o | 310 | +VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o |
311 | 311 | ||
312 | # PCI network cards | 312 | # PCI network cards |
313 | VL_OBJS+= ne2000.o rtl8139.o | 313 | VL_OBJS+= ne2000.o rtl8139.o |
hw/pc.c
@@ -40,7 +40,6 @@ static fdctrl_t *floppy_controller; | @@ -40,7 +40,6 @@ static fdctrl_t *floppy_controller; | ||
40 | static RTCState *rtc_state; | 40 | static RTCState *rtc_state; |
41 | static PITState *pit; | 41 | static PITState *pit; |
42 | static IOAPICState *ioapic; | 42 | static IOAPICState *ioapic; |
43 | -static USBPort *usb_root_ports[2]; | ||
44 | 43 | ||
45 | static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) | 44 | static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) |
46 | { | 45 | { |
@@ -833,8 +832,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, | @@ -833,8 +832,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, | ||
833 | cmos_init(ram_size, boot_device, bs_table); | 832 | cmos_init(ram_size, boot_device, bs_table); |
834 | 833 | ||
835 | if (pci_enabled && usb_enabled) { | 834 | if (pci_enabled && usb_enabled) { |
836 | - usb_uhci_init(pci_bus, usb_root_ports, piix3_devfn + 2); | ||
837 | - usb_attach(usb_root_ports[0], vm_usb_hub); | 835 | + usb_uhci_init(pci_bus, piix3_devfn + 2); |
838 | } | 836 | } |
839 | 837 | ||
840 | if (pci_enabled && acpi_enabled) { | 838 | if (pci_enabled && acpi_enabled) { |
hw/ppc_chrp.c
@@ -506,7 +506,11 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, | @@ -506,7 +506,11 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, | ||
506 | 506 | ||
507 | arch_name = "MAC99"; | 507 | arch_name = "MAC99"; |
508 | } | 508 | } |
509 | - | 509 | + |
510 | + if (usb_enabled) { | ||
511 | + usb_ohci_init(pci_bus, 3, -1); | ||
512 | + } | ||
513 | + | ||
510 | if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) | 514 | if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) |
511 | graphic_depth = 15; | 515 | graphic_depth = 15; |
512 | 516 |
hw/ppc_prep.c
@@ -665,6 +665,10 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, | @@ -665,6 +665,10 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, | ||
665 | cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); | 665 | cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); |
666 | #endif | 666 | #endif |
667 | 667 | ||
668 | + if (usb_enabled) { | ||
669 | + usb_ohci_init(pci_bus, 3, -1); | ||
670 | + } | ||
671 | + | ||
668 | nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); | 672 | nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); |
669 | if (nvram == NULL) | 673 | if (nvram == NULL) |
670 | return; | 674 | return; |
hw/usb-hub.c
@@ -179,6 +179,9 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) | @@ -179,6 +179,9 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) | ||
179 | else | 179 | else |
180 | port->wPortStatus &= ~PORT_STAT_LOW_SPEED; | 180 | port->wPortStatus &= ~PORT_STAT_LOW_SPEED; |
181 | port->port.dev = dev; | 181 | port->port.dev = dev; |
182 | + /* send the attach message */ | ||
183 | + dev->handle_packet(dev, | ||
184 | + USB_MSG_ATTACH, 0, 0, NULL, 0); | ||
182 | } else { | 185 | } else { |
183 | dev = port->port.dev; | 186 | dev = port->port.dev; |
184 | if (dev) { | 187 | if (dev) { |
@@ -188,6 +191,9 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) | @@ -188,6 +191,9 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) | ||
188 | port->wPortStatus &= ~PORT_STAT_ENABLE; | 191 | port->wPortStatus &= ~PORT_STAT_ENABLE; |
189 | port->wPortChange |= PORT_STAT_C_ENABLE; | 192 | port->wPortChange |= PORT_STAT_C_ENABLE; |
190 | } | 193 | } |
194 | + /* send the detach message */ | ||
195 | + dev->handle_packet(dev, | ||
196 | + USB_MSG_DETACH, 0, 0, NULL, 0); | ||
191 | port->port.dev = NULL; | 197 | port->port.dev = NULL; |
192 | } | 198 | } |
193 | } | 199 | } |
@@ -517,7 +523,7 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid, | @@ -517,7 +523,7 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid, | ||
517 | return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); | 523 | return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); |
518 | } | 524 | } |
519 | 525 | ||
520 | -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) | 526 | +USBDevice *usb_hub_init(int nb_ports) |
521 | { | 527 | { |
522 | USBHubState *s; | 528 | USBHubState *s; |
523 | USBHubPort *port; | 529 | USBHubPort *port; |
@@ -539,12 +545,9 @@ USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) | @@ -539,12 +545,9 @@ USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) | ||
539 | s->nb_ports = nb_ports; | 545 | s->nb_ports = nb_ports; |
540 | for(i = 0; i < s->nb_ports; i++) { | 546 | for(i = 0; i < s->nb_ports; i++) { |
541 | port = &s->ports[i]; | 547 | port = &s->ports[i]; |
548 | + qemu_register_usb_port(&port->port, s, i, usb_hub_attach); | ||
542 | port->wPortStatus = PORT_STAT_POWER; | 549 | port->wPortStatus = PORT_STAT_POWER; |
543 | port->wPortChange = 0; | 550 | port->wPortChange = 0; |
544 | - port->port.attach = usb_hub_attach; | ||
545 | - port->port.opaque = s; | ||
546 | - port->port.index = i; | ||
547 | - usb_ports[i] = &port->port; | ||
548 | } | 551 | } |
549 | return (USBDevice *)s; | 552 | return (USBDevice *)s; |
550 | } | 553 | } |
hw/usb-ohci.c
0 โ 100644
1 | +/* | ||
2 | + * QEMU USB OHCI Emulation | ||
3 | + * Copyright (c) 2004 Gianni Tedesco | ||
4 | + * Copyright (c) 2006 CodeSourcery | ||
5 | + * | ||
6 | + * This library is free software; you can redistribute it and/or | ||
7 | + * modify it under the terms of the GNU Lesser General Public | ||
8 | + * License as published by the Free Software Foundation; either | ||
9 | + * version 2 of the License, or (at your option) any later version. | ||
10 | + * | ||
11 | + * This library is distributed in the hope that it will be useful, | ||
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | + * Lesser General Public License for more details. | ||
15 | + * | ||
16 | + * You should have received a copy of the GNU Lesser General Public | ||
17 | + * License along with this library; if not, write to the Free Software | ||
18 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | + * | ||
20 | + * TODO: | ||
21 | + * o Isochronous transfers | ||
22 | + * o Allocate bandwidth in frames properly | ||
23 | + * o Disable timers when nothing needs to be done, or remove timer usage | ||
24 | + * all together. | ||
25 | + * o Handle unrecoverable errors properly | ||
26 | + * o BIOS work to boot from USB storage | ||
27 | +*/ | ||
28 | + | ||
29 | +#include "vl.h" | ||
30 | + | ||
31 | +//#define DEBUG_OHCI | ||
32 | +/* Dump packet contents. */ | ||
33 | +//#define DEBUG_PACKET | ||
34 | +/* This causes frames to occur 1000x slower */ | ||
35 | +//#define OHCI_TIME_WARP 1 | ||
36 | + | ||
37 | +#ifdef DEBUG_OHCI | ||
38 | +#define dprintf printf | ||
39 | +#else | ||
40 | +#define dprintf(...) | ||
41 | +#endif | ||
42 | + | ||
43 | +/* Number of Downstream Ports on the root hub. */ | ||
44 | + | ||
45 | +#define OHCI_MAX_PORTS 15 | ||
46 | + | ||
47 | +static int64_t usb_frame_time; | ||
48 | +static int64_t usb_bit_time; | ||
49 | + | ||
50 | +typedef struct OHCIPort { | ||
51 | + USBPort port; | ||
52 | + uint32_t ctrl; | ||
53 | +} OHCIPort; | ||
54 | + | ||
55 | +typedef struct { | ||
56 | + struct PCIDevice pci_dev; | ||
57 | + target_phys_addr_t mem_base; | ||
58 | + int mem; | ||
59 | + int num_ports; | ||
60 | + | ||
61 | + QEMUTimer *eof_timer; | ||
62 | + int64_t sof_time; | ||
63 | + | ||
64 | + /* OHCI state */ | ||
65 | + /* Control partition */ | ||
66 | + uint32_t ctl, status; | ||
67 | + uint32_t intr_status; | ||
68 | + uint32_t intr; | ||
69 | + | ||
70 | + /* memory pointer partition */ | ||
71 | + uint32_t hcca; | ||
72 | + uint32_t ctrl_head, ctrl_cur; | ||
73 | + uint32_t bulk_head, bulk_cur; | ||
74 | + uint32_t per_cur; | ||
75 | + uint32_t done; | ||
76 | + int done_count; | ||
77 | + | ||
78 | + /* Frame counter partition */ | ||
79 | + uint32_t fsmps:15; | ||
80 | + uint32_t fit:1; | ||
81 | + uint32_t fi:14; | ||
82 | + uint32_t frt:1; | ||
83 | + uint16_t frame_number; | ||
84 | + uint16_t padding; | ||
85 | + uint32_t pstart; | ||
86 | + uint32_t lst; | ||
87 | + | ||
88 | + /* Root Hub partition */ | ||
89 | + uint32_t rhdesc_a, rhdesc_b; | ||
90 | + uint32_t rhstatus; | ||
91 | + OHCIPort rhport[OHCI_MAX_PORTS]; | ||
92 | +} OHCIState; | ||
93 | + | ||
94 | +/* Host Controller Communications Area */ | ||
95 | +struct ohci_hcca { | ||
96 | + uint32_t intr[32]; | ||
97 | + uint16_t frame, pad; | ||
98 | + uint32_t done; | ||
99 | +}; | ||
100 | + | ||
101 | +/* Bitfields for the first word of an Endpoint Desciptor. */ | ||
102 | +#define OHCI_ED_FA_SHIFT 0 | ||
103 | +#define OHCI_ED_FA_MASK (0x7f<<OHCI_ED_FA_SHIFT) | ||
104 | +#define OHCI_ED_EN_SHIFT 7 | ||
105 | +#define OHCI_ED_EN_MASK (0xf<<OHCI_ED_EN_SHIFT) | ||
106 | +#define OHCI_ED_D_SHIFT 11 | ||
107 | +#define OHCI_ED_D_MASK (3<<OHCI_ED_D_SHIFT) | ||
108 | +#define OHCI_ED_S (1<<13) | ||
109 | +#define OHCI_ED_K (1<<14) | ||
110 | +#define OHCI_ED_F (1<<15) | ||
111 | +#define OHCI_ED_MPS_SHIFT 7 | ||
112 | +#define OHCI_ED_MPS_MASK (0xf<<OHCI_ED_FA_SHIFT) | ||
113 | + | ||
114 | +/* Flags in the head field of an Endpoint Desciptor. */ | ||
115 | +#define OHCI_ED_H 1 | ||
116 | +#define OHCI_ED_C 2 | ||
117 | + | ||
118 | +/* Bitfields for the first word of a Transfer Desciptor. */ | ||
119 | +#define OHCI_TD_R (1<<18) | ||
120 | +#define OHCI_TD_DP_SHIFT 19 | ||
121 | +#define OHCI_TD_DP_MASK (3<<OHCI_TD_DP_SHIFT) | ||
122 | +#define OHCI_TD_DI_SHIFT 21 | ||
123 | +#define OHCI_TD_DI_MASK (7<<OHCI_TD_DI_SHIFT) | ||
124 | +#define OHCI_TD_T0 (1<<24) | ||
125 | +#define OHCI_TD_T1 (1<<24) | ||
126 | +#define OHCI_TD_EC_SHIFT 26 | ||
127 | +#define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT) | ||
128 | +#define OHCI_TD_CC_SHIFT 28 | ||
129 | +#define OHCI_TD_CC_MASK (0xf<<OHCI_TD_CC_SHIFT) | ||
130 | + | ||
131 | +#define OHCI_DPTR_MASK 0xfffffff0 | ||
132 | + | ||
133 | +#define OHCI_BM(val, field) \ | ||
134 | + (((val) & OHCI_##field##_MASK) >> OHCI_##field##_SHIFT) | ||
135 | + | ||
136 | +#define OHCI_SET_BM(val, field, newval) do { \ | ||
137 | + val &= ~OHCI_##field##_MASK; \ | ||
138 | + val |= ((newval) << OHCI_##field##_SHIFT) & OHCI_##field##_MASK; \ | ||
139 | + } while(0) | ||
140 | + | ||
141 | +/* endpoint descriptor */ | ||
142 | +struct ohci_ed { | ||
143 | + uint32_t flags; | ||
144 | + uint32_t tail; | ||
145 | + uint32_t head; | ||
146 | + uint32_t next; | ||
147 | +}; | ||
148 | + | ||
149 | +/* General transfer descriptor */ | ||
150 | +struct ohci_td { | ||
151 | + uint32_t flags; | ||
152 | + uint32_t cbp; | ||
153 | + uint32_t next; | ||
154 | + uint32_t be; | ||
155 | +}; | ||
156 | + | ||
157 | +#define USB_HZ 12000000 | ||
158 | + | ||
159 | +/* OHCI Local stuff */ | ||
160 | +#define OHCI_CTL_CBSR ((1<<0)|(1<<1)) | ||
161 | +#define OHCI_CTL_PLE (1<<2) | ||
162 | +#define OHCI_CTL_IE (1<<3) | ||
163 | +#define OHCI_CTL_CLE (1<<4) | ||
164 | +#define OHCI_CTL_BLE (1<<5) | ||
165 | +#define OHCI_CTL_HCFS ((1<<6)|(1<<7)) | ||
166 | +#define OHCI_USB_RESET 0x00 | ||
167 | +#define OHCI_USB_RESUME 0x40 | ||
168 | +#define OHCI_USB_OPERATIONAL 0x80 | ||
169 | +#define OHCI_USB_SUSPEND 0xc0 | ||
170 | +#define OHCI_CTL_IR (1<<8) | ||
171 | +#define OHCI_CTL_RWC (1<<9) | ||
172 | +#define OHCI_CTL_RWE (1<<10) | ||
173 | + | ||
174 | +#define OHCI_STATUS_HCR (1<<0) | ||
175 | +#define OHCI_STATUS_CLF (1<<1) | ||
176 | +#define OHCI_STATUS_BLF (1<<2) | ||
177 | +#define OHCI_STATUS_OCR (1<<3) | ||
178 | +#define OHCI_STATUS_SOC ((1<<6)|(1<<7)) | ||
179 | + | ||
180 | +#define OHCI_INTR_SO (1<<0) /* Scheduling overrun */ | ||
181 | +#define OHCI_INTR_WD (1<<1) /* HcDoneHead writeback */ | ||
182 | +#define OHCI_INTR_SF (1<<2) /* Start of frame */ | ||
183 | +#define OHCI_INTR_RD (1<<3) /* Resume detect */ | ||
184 | +#define OHCI_INTR_UE (1<<4) /* Unrecoverable error */ | ||
185 | +#define OHCI_INTR_FNO (1<<5) /* Frame number overflow */ | ||
186 | +#define OHCI_INTR_RHSC (1<<6) /* Root hub status change */ | ||
187 | +#define OHCI_INTR_OC (1<<30) /* Ownership change */ | ||
188 | +#define OHCI_INTR_MIE (1<<31) /* Master Interrupt Enable */ | ||
189 | + | ||
190 | +#define OHCI_HCCA_SIZE 0x100 | ||
191 | +#define OHCI_HCCA_MASK 0xffffff00 | ||
192 | + | ||
193 | +#define OHCI_EDPTR_MASK 0xfffffff0 | ||
194 | + | ||
195 | +#define OHCI_FMI_FI 0x00003fff | ||
196 | +#define OHCI_FMI_FSMPS 0xffff0000 | ||
197 | +#define OHCI_FMI_FIT 0x80000000 | ||
198 | + | ||
199 | +#define OHCI_FR_RT (1<<31) | ||
200 | + | ||
201 | +#define OHCI_LS_THRESH 0x628 | ||
202 | + | ||
203 | +#define OHCI_RHA_RW_MASK 0x00000000 /* Mask of supported features. */ | ||
204 | +#define OHCI_RHA_PSM (1<<8) | ||
205 | +#define OHCI_RHA_NPS (1<<9) | ||
206 | +#define OHCI_RHA_DT (1<<10) | ||
207 | +#define OHCI_RHA_OCPM (1<<11) | ||
208 | +#define OHCI_RHA_NOCP (1<<12) | ||
209 | +#define OHCI_RHA_POTPGT_MASK 0xff000000 | ||
210 | + | ||
211 | +#define OHCI_RHS_LPS (1<<0) | ||
212 | +#define OHCI_RHS_OCI (1<<1) | ||
213 | +#define OHCI_RHS_DRWE (1<<15) | ||
214 | +#define OHCI_RHS_LPSC (1<<16) | ||
215 | +#define OHCI_RHS_OCIC (1<<17) | ||
216 | +#define OHCI_RHS_CRWE (1<<31) | ||
217 | + | ||
218 | +#define OHCI_PORT_CCS (1<<0) | ||
219 | +#define OHCI_PORT_PES (1<<1) | ||
220 | +#define OHCI_PORT_PSS (1<<2) | ||
221 | +#define OHCI_PORT_POCI (1<<3) | ||
222 | +#define OHCI_PORT_PRS (1<<4) | ||
223 | +#define OHCI_PORT_PPS (1<<8) | ||
224 | +#define OHCI_PORT_LSDA (1<<9) | ||
225 | +#define OHCI_PORT_CSC (1<<16) | ||
226 | +#define OHCI_PORT_PESC (1<<17) | ||
227 | +#define OHCI_PORT_PSSC (1<<18) | ||
228 | +#define OHCI_PORT_OCIC (1<<19) | ||
229 | +#define OHCI_PORT_PRSC (1<<20) | ||
230 | +#define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \ | ||
231 | + |OHCI_PORT_OCIC|OHCI_PORT_PRSC) | ||
232 | + | ||
233 | +#define OHCI_TD_DIR_SETUP 0x0 | ||
234 | +#define OHCI_TD_DIR_OUT 0x1 | ||
235 | +#define OHCI_TD_DIR_IN 0x2 | ||
236 | +#define OHCI_TD_DIR_RESERVED 0x3 | ||
237 | + | ||
238 | +#define OHCI_CC_NOERROR 0x0 | ||
239 | +#define OHCI_CC_CRC 0x1 | ||
240 | +#define OHCI_CC_BITSTUFFING 0x2 | ||
241 | +#define OHCI_CC_DATATOGGLEMISMATCH 0x3 | ||
242 | +#define OHCI_CC_STALL 0x4 | ||
243 | +#define OHCI_CC_DEVICENOTRESPONDING 0x5 | ||
244 | +#define OHCI_CC_PIDCHECKFAILURE 0x6 | ||
245 | +#define OHCI_CC_UNDEXPETEDPID 0x7 | ||
246 | +#define OHCI_CC_DATAOVERRUN 0x8 | ||
247 | +#define OHCI_CC_DATAUNDERRUN 0x9 | ||
248 | +#define OHCI_CC_BUFFEROVERRUN 0xc | ||
249 | +#define OHCI_CC_BUFFERUNDERRUN 0xd | ||
250 | + | ||
251 | +static void ohci_attach(USBPort *port1, USBDevice *dev) | ||
252 | +{ | ||
253 | + OHCIState *s = port1->opaque; | ||
254 | + OHCIPort *port = &s->rhport[port1->index]; | ||
255 | + | ||
256 | + if (dev) { | ||
257 | + if (port->port.dev) { | ||
258 | + usb_attach(port1, NULL); | ||
259 | + } | ||
260 | + /* set connect status */ | ||
261 | + if (!(port->ctrl & OHCI_PORT_CCS)) { | ||
262 | + port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; | ||
263 | + } | ||
264 | + /* update speed */ | ||
265 | + if (dev->speed == USB_SPEED_LOW) | ||
266 | + port->ctrl |= OHCI_PORT_LSDA; | ||
267 | + else | ||
268 | + port->ctrl &= ~OHCI_PORT_LSDA; | ||
269 | + port->port.dev = dev; | ||
270 | + /* send the attach message */ | ||
271 | + dev->handle_packet(dev, | ||
272 | + USB_MSG_ATTACH, 0, 0, NULL, 0); | ||
273 | + dprintf("usb-ohci: Attached port %d\n", port1->index); | ||
274 | + } else { | ||
275 | + /* set connect status */ | ||
276 | + if (!(port->ctrl & OHCI_PORT_CCS)) { | ||
277 | + port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; | ||
278 | + } | ||
279 | + /* disable port */ | ||
280 | + if (port->ctrl & OHCI_PORT_PES) { | ||
281 | + port->ctrl &= ~OHCI_PORT_PES; | ||
282 | + port->ctrl |= OHCI_PORT_PESC; | ||
283 | + } | ||
284 | + dev = port->port.dev; | ||
285 | + if (dev) { | ||
286 | + /* send the detach message */ | ||
287 | + dev->handle_packet(dev, | ||
288 | + USB_MSG_DETACH, 0, 0, NULL, 0); | ||
289 | + } | ||
290 | + port->port.dev = NULL; | ||
291 | + dprintf("usb-ohci: Detached port %d\n", port1->index); | ||
292 | + } | ||
293 | +} | ||
294 | + | ||
295 | +/* Reset the controller */ | ||
296 | +static void ohci_reset(OHCIState *ohci) | ||
297 | +{ | ||
298 | + OHCIPort *port; | ||
299 | + int i; | ||
300 | + | ||
301 | + ohci->ctl = 0; | ||
302 | + ohci->status = 0; | ||
303 | + ohci->intr_status = 0; | ||
304 | + ohci->intr = OHCI_INTR_MIE; | ||
305 | + | ||
306 | + ohci->hcca = 0; | ||
307 | + ohci->ctrl_head = ohci->ctrl_cur = 0; | ||
308 | + ohci->bulk_head = ohci->bulk_cur = 0; | ||
309 | + ohci->per_cur = 0; | ||
310 | + ohci->done = 0; | ||
311 | + ohci->done_count = 7; | ||
312 | + | ||
313 | + /* FSMPS is marked TBD in OCHI 1.0, what gives ffs? | ||
314 | + * I took the value linux sets ... | ||
315 | + */ | ||
316 | + ohci->fsmps = 0x2778; | ||
317 | + ohci->fi = 0x2edf; | ||
318 | + ohci->fit = 0; | ||
319 | + ohci->frt = 0; | ||
320 | + ohci->frame_number = 0; | ||
321 | + ohci->pstart = 0; | ||
322 | + ohci->lst = OHCI_LS_THRESH; | ||
323 | + | ||
324 | + ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports; | ||
325 | + ohci->rhdesc_b = 0x0; /* Impl. specific */ | ||
326 | + ohci->rhstatus = 0; | ||
327 | + | ||
328 | + for (i = 0; i < ohci->num_ports; i++) | ||
329 | + { | ||
330 | + port = &ohci->rhport[i]; | ||
331 | + port->ctrl = 0; | ||
332 | + if (port->port.dev) | ||
333 | + ohci_attach(&port->port, port->port.dev); | ||
334 | + } | ||
335 | + dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); | ||
336 | +} | ||
337 | + | ||
338 | +/* Update IRQ levels */ | ||
339 | +static inline void ohci_intr_update(OHCIState *ohci) | ||
340 | +{ | ||
341 | + int level = 0; | ||
342 | + | ||
343 | + if ((ohci->intr & OHCI_INTR_MIE) && | ||
344 | + (ohci->intr_status & ohci->intr)) | ||
345 | + level = 1; | ||
346 | + | ||
347 | + pci_set_irq(&ohci->pci_dev, 0, level); | ||
348 | +} | ||
349 | + | ||
350 | +/* Set an interrupt */ | ||
351 | +static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) | ||
352 | +{ | ||
353 | + ohci->intr_status |= intr; | ||
354 | + ohci_intr_update(ohci); | ||
355 | +} | ||
356 | + | ||
357 | +/* Get an array of dwords from main memory */ | ||
358 | +static inline int get_dwords(uint32_t addr, uint32_t *buf, int num) | ||
359 | +{ | ||
360 | + int i; | ||
361 | + | ||
362 | + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { | ||
363 | + cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0); | ||
364 | + *buf = le32_to_cpu(*buf); | ||
365 | + } | ||
366 | + | ||
367 | + return 1; | ||
368 | +} | ||
369 | + | ||
370 | +/* Put an array of dwords in to main memory */ | ||
371 | +static inline int put_dwords(uint32_t addr, uint32_t *buf, int num) | ||
372 | +{ | ||
373 | + int i; | ||
374 | + | ||
375 | + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { | ||
376 | + uint32_t tmp = cpu_to_le32(*buf); | ||
377 | + cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1); | ||
378 | + } | ||
379 | + | ||
380 | + return 1; | ||
381 | +} | ||
382 | + | ||
383 | +static inline int ohci_read_ed(uint32_t addr, struct ohci_ed *ed) | ||
384 | +{ | ||
385 | + return get_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2); | ||
386 | +} | ||
387 | + | ||
388 | +static inline int ohci_read_td(uint32_t addr, struct ohci_td *td) | ||
389 | +{ | ||
390 | + return get_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2); | ||
391 | +} | ||
392 | + | ||
393 | +static inline int ohci_put_ed(uint32_t addr, struct ohci_ed *ed) | ||
394 | +{ | ||
395 | + return put_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2); | ||
396 | +} | ||
397 | + | ||
398 | +static inline int ohci_put_td(uint32_t addr, struct ohci_td *td) | ||
399 | +{ | ||
400 | + return put_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2); | ||
401 | +} | ||
402 | + | ||
403 | +/* Read/Write the contents of a TD from/to main memory. */ | ||
404 | +static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write) | ||
405 | +{ | ||
406 | + uint32_t ptr; | ||
407 | + uint32_t n; | ||
408 | + | ||
409 | + ptr = td->cbp; | ||
410 | + n = 0x1000 - (ptr & 0xfff); | ||
411 | + if (n > len) | ||
412 | + n = len; | ||
413 | + cpu_physical_memory_rw(ptr, buf, n, write); | ||
414 | + if (n == len) | ||
415 | + return; | ||
416 | + ptr = td->be & ~0xfffu; | ||
417 | + cpu_physical_memory_rw(ptr, buf, len - n, write); | ||
418 | +} | ||
419 | + | ||
420 | +/* Service a transport descriptor. | ||
421 | + Returns nonzero to terminate processing of this endpoint. */ | ||
422 | + | ||
423 | +static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) | ||
424 | +{ | ||
425 | + int dir; | ||
426 | + size_t len = 0; | ||
427 | + uint8_t buf[8192]; | ||
428 | + char *str = NULL; | ||
429 | + int pid; | ||
430 | + int ret; | ||
431 | + int i; | ||
432 | + USBDevice *dev; | ||
433 | + struct ohci_td td; | ||
434 | + uint32_t addr; | ||
435 | + int flag_r; | ||
436 | + | ||
437 | + addr = ed->head & OHCI_DPTR_MASK; | ||
438 | + if (!ohci_read_td(addr, &td)) { | ||
439 | + fprintf(stderr, "usb-ohci: TD read error at %x\n", addr); | ||
440 | + return 0; | ||
441 | + } | ||
442 | + | ||
443 | + dir = OHCI_BM(ed->flags, ED_D); | ||
444 | + switch (dir) { | ||
445 | + case OHCI_TD_DIR_OUT: | ||
446 | + case OHCI_TD_DIR_IN: | ||
447 | + /* Same value. */ | ||
448 | + break; | ||
449 | + default: | ||
450 | + dir = OHCI_BM(td.flags, TD_DP); | ||
451 | + break; | ||
452 | + } | ||
453 | + | ||
454 | + switch (dir) { | ||
455 | + case OHCI_TD_DIR_IN: | ||
456 | + str = "in"; | ||
457 | + pid = USB_TOKEN_IN; | ||
458 | + break; | ||
459 | + case OHCI_TD_DIR_OUT: | ||
460 | + str = "out"; | ||
461 | + pid = USB_TOKEN_OUT; | ||
462 | + break; | ||
463 | + case OHCI_TD_DIR_SETUP: | ||
464 | + str = "setup"; | ||
465 | + pid = USB_TOKEN_SETUP; | ||
466 | + break; | ||
467 | + default: | ||
468 | + fprintf(stderr, "usb-ohci: Bad direction\n"); | ||
469 | + return 1; | ||
470 | + } | ||
471 | + if (td.cbp && td.be) { | ||
472 | + len = (td.be - td.cbp) + 1; | ||
473 | + if (len && dir != OHCI_TD_DIR_IN) { | ||
474 | + ohci_copy_td(&td, buf, len, 0); | ||
475 | + } | ||
476 | + } | ||
477 | + | ||
478 | + flag_r = (td.flags & OHCI_TD_R) != 0; | ||
479 | +#ifdef DEBUG_PACKET | ||
480 | + dprintf(" TD @ 0x%.8x %u bytes %s r=%d cbp=0x%.8x be=0x%.8x\n", | ||
481 | + addr, len, str, flag_r, td.cbp, td.be); | ||
482 | + | ||
483 | + if (len >= 0 && dir != OHCI_TD_DIR_IN) { | ||
484 | + dprintf(" data:"); | ||
485 | + for (i = 0; i < len; i++) | ||
486 | + printf(" %.2x", buf[i]); | ||
487 | + dprintf("\n"); | ||
488 | + } | ||
489 | +#endif | ||
490 | + ret = USB_RET_NODEV; | ||
491 | + for (i = 0; i < ohci->num_ports; i++) { | ||
492 | + dev = ohci->rhport[i].port.dev; | ||
493 | + if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0) | ||
494 | + continue; | ||
495 | + | ||
496 | + ret = dev->handle_packet(dev, pid, OHCI_BM(ed->flags, ED_FA), | ||
497 | + OHCI_BM(ed->flags, ED_EN), buf, len); | ||
498 | + if (ret != USB_RET_NODEV) | ||
499 | + break; | ||
500 | + } | ||
501 | +#ifdef DEBUG_PACKET | ||
502 | + dprintf("ret=%d\n", ret); | ||
503 | +#endif | ||
504 | + if (ret >= 0) { | ||
505 | + if (dir == OHCI_TD_DIR_IN) { | ||
506 | + ohci_copy_td(&td, buf, ret, 1); | ||
507 | +#ifdef DEBUG_PACKET | ||
508 | + dprintf(" data:"); | ||
509 | + for (i = 0; i < ret; i++) | ||
510 | + printf(" %.2x", buf[i]); | ||
511 | + dprintf("\n"); | ||
512 | +#endif | ||
513 | + } else { | ||
514 | + ret = len; | ||
515 | + } | ||
516 | + } | ||
517 | + | ||
518 | + /* Writeback */ | ||
519 | + if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) { | ||
520 | + /* Transmission succeeded. */ | ||
521 | + if (ret == len) { | ||
522 | + td.cbp = 0; | ||
523 | + } else { | ||
524 | + td.cbp += ret; | ||
525 | + if ((td.cbp & 0xfff) + ret > 0xfff) { | ||
526 | + td.cbp &= 0xfff; | ||
527 | + td.cbp |= td.be & ~0xfff; | ||
528 | + } | ||
529 | + } | ||
530 | + td.flags |= OHCI_TD_T1; | ||
531 | + td.flags ^= OHCI_TD_T0; | ||
532 | + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR); | ||
533 | + OHCI_SET_BM(td.flags, TD_EC, 0); | ||
534 | + | ||
535 | + ed->head &= ~OHCI_ED_C; | ||
536 | + if (td.flags & OHCI_TD_T0) | ||
537 | + ed->head |= OHCI_ED_C; | ||
538 | + } else { | ||
539 | + if (ret >= 0) { | ||
540 | + dprintf("usb-ohci: Underrun\n"); | ||
541 | + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); | ||
542 | + } else { | ||
543 | + switch (ret) { | ||
544 | + case USB_RET_NODEV: | ||
545 | + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); | ||
546 | + case USB_RET_NAK: | ||
547 | + dprintf("usb-ohci: got NAK\n"); | ||
548 | + return 1; | ||
549 | + case USB_RET_STALL: | ||
550 | + dprintf("usb-ohci: got STALL\n"); | ||
551 | + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_STALL); | ||
552 | + break; | ||
553 | + case USB_RET_BABBLE: | ||
554 | + dprintf("usb-ohci: got BABBLE\n"); | ||
555 | + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAOVERRUN); | ||
556 | + break; | ||
557 | + default: | ||
558 | + fprintf(stderr, "usb-ohci: Bad device response %d\n", ret); | ||
559 | + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_UNDEXPETEDPID); | ||
560 | + OHCI_SET_BM(td.flags, TD_EC, 3); | ||
561 | + break; | ||
562 | + } | ||
563 | + } | ||
564 | + ed->head |= OHCI_ED_H; | ||
565 | + } | ||
566 | + | ||
567 | + /* Retire this TD */ | ||
568 | + ed->head &= ~OHCI_DPTR_MASK; | ||
569 | + ed->head |= td.next & OHCI_DPTR_MASK; | ||
570 | + td.next = ohci->done; | ||
571 | + ohci->done = addr; | ||
572 | + i = OHCI_BM(td.flags, TD_DI); | ||
573 | + if (i < ohci->done_count) | ||
574 | + ohci->done_count = i; | ||
575 | + ohci_put_td(addr, &td); | ||
576 | + return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; | ||
577 | +} | ||
578 | + | ||
579 | +/* Service an endpoint list. Returns nonzero if active TD were found. */ | ||
580 | +static int ohci_service_ed_list(OHCIState *ohci, uint32_t head) | ||
581 | +{ | ||
582 | + struct ohci_ed ed; | ||
583 | + uint32_t next_ed; | ||
584 | + uint32_t cur; | ||
585 | + int active; | ||
586 | + | ||
587 | + active = 0; | ||
588 | + | ||
589 | + if (head == 0) | ||
590 | + return 0; | ||
591 | + | ||
592 | + for (cur = head; cur; cur = next_ed) { | ||
593 | + if (!ohci_read_ed(cur, &ed)) { | ||
594 | + fprintf(stderr, "usb-ohci: ED read error at %x\n", cur); | ||
595 | + return 0; | ||
596 | + } | ||
597 | + | ||
598 | + next_ed = ed.next & OHCI_DPTR_MASK; | ||
599 | + | ||
600 | + if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) | ||
601 | + continue; | ||
602 | + | ||
603 | + /* Skip isochronous endpoints. */ | ||
604 | + if (ed.flags & OHCI_ED_F) | ||
605 | + continue; | ||
606 | + | ||
607 | + while ((ed.head & OHCI_DPTR_MASK) != ed.tail) { | ||
608 | +#ifdef DEBUG_PACKET | ||
609 | + dprintf("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u " | ||
610 | + "h=%u c=%u\n head=0x%.8x tailp=0x%.8x next=0x%.8x\n", cur, | ||
611 | + OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN), | ||
612 | + OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S)!= 0, | ||
613 | + (ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0, | ||
614 | + OHCI_BM(ed.flags, ED_MPS), (ed.head & OHCI_ED_H) != 0, | ||
615 | + (ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK, | ||
616 | + ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK); | ||
617 | +#endif | ||
618 | + active = 1; | ||
619 | + | ||
620 | + if (ohci_service_td(ohci, &ed)) | ||
621 | + break; | ||
622 | + } | ||
623 | + | ||
624 | + ohci_put_ed(cur, &ed); | ||
625 | + } | ||
626 | + | ||
627 | + return active; | ||
628 | +} | ||
629 | + | ||
630 | +/* Generate a SOF event, and set a timer for EOF */ | ||
631 | +static void ohci_sof(OHCIState *ohci) | ||
632 | +{ | ||
633 | + ohci->sof_time = qemu_get_clock(vm_clock); | ||
634 | + qemu_mod_timer(ohci->eof_timer, ohci->sof_time + usb_frame_time); | ||
635 | + ohci_set_interrupt(ohci, OHCI_INTR_SF); | ||
636 | +} | ||
637 | + | ||
638 | +/* Do frame processing on frame boundary */ | ||
639 | +static void ohci_frame_boundary(void *opaque) | ||
640 | +{ | ||
641 | + OHCIState *ohci = opaque; | ||
642 | + struct ohci_hcca hcca; | ||
643 | + | ||
644 | + cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 0); | ||
645 | + | ||
646 | + /* Process all the lists at the end of the frame */ | ||
647 | + if (ohci->ctl & OHCI_CTL_PLE) { | ||
648 | + int n; | ||
649 | + | ||
650 | + n = ohci->frame_number & 0x1f; | ||
651 | + ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n])); | ||
652 | + } | ||
653 | + if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) { | ||
654 | + if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) | ||
655 | + dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur); | ||
656 | + if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) { | ||
657 | + ohci->ctrl_cur = 0; | ||
658 | + ohci->status &= ~OHCI_STATUS_CLF; | ||
659 | + } | ||
660 | + } | ||
661 | + | ||
662 | + if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) { | ||
663 | + if (!ohci_service_ed_list(ohci, ohci->bulk_head)) { | ||
664 | + ohci->bulk_cur = 0; | ||
665 | + ohci->status &= ~OHCI_STATUS_BLF; | ||
666 | + } | ||
667 | + } | ||
668 | + | ||
669 | + /* Frame boundary, so do EOF stuf here */ | ||
670 | + ohci->frt = ohci->fit; | ||
671 | + | ||
672 | + /* XXX: endianness */ | ||
673 | + ohci->frame_number = (ohci->frame_number + 1) & 0xffff; | ||
674 | + hcca.frame = cpu_to_le32(ohci->frame_number); | ||
675 | + | ||
676 | + if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) { | ||
677 | + if (!ohci->done) | ||
678 | + abort(); | ||
679 | + if (ohci->intr & ohci->intr_status) | ||
680 | + ohci->done |= 1; | ||
681 | + hcca.done = cpu_to_le32(ohci->done); | ||
682 | + ohci->done = 0; | ||
683 | + ohci->done_count = 7; | ||
684 | + ohci_set_interrupt(ohci, OHCI_INTR_WD); | ||
685 | + } | ||
686 | + | ||
687 | + if (ohci->done_count != 7 && ohci->done_count != 0) | ||
688 | + ohci->done_count--; | ||
689 | + | ||
690 | + /* Do SOF stuff here */ | ||
691 | + ohci_sof(ohci); | ||
692 | + | ||
693 | + /* Writeback HCCA */ | ||
694 | + cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 1); | ||
695 | +} | ||
696 | + | ||
697 | +/* Start sending SOF tokens across the USB bus, lists are processed in | ||
698 | + * next frame | ||
699 | + */ | ||
700 | +static int ohci_bus_start(OHCIState *ohci) | ||
701 | +{ | ||
702 | + ohci->eof_timer = qemu_new_timer(vm_clock, | ||
703 | + ohci_frame_boundary, | ||
704 | + ohci); | ||
705 | + | ||
706 | + if (ohci->eof_timer == NULL) { | ||
707 | + fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n", | ||
708 | + ohci->pci_dev.name); | ||
709 | + /* TODO: Signal unrecoverable error */ | ||
710 | + return 0; | ||
711 | + } | ||
712 | + | ||
713 | + dprintf("usb-ohci: %s: USB Operational\n", ohci->pci_dev.name); | ||
714 | + | ||
715 | + ohci_sof(ohci); | ||
716 | + | ||
717 | + return 1; | ||
718 | +} | ||
719 | + | ||
720 | +/* Stop sending SOF tokens on the bus */ | ||
721 | +static void ohci_bus_stop(OHCIState *ohci) | ||
722 | +{ | ||
723 | + if (ohci->eof_timer) | ||
724 | + qemu_del_timer(ohci->eof_timer); | ||
725 | +} | ||
726 | + | ||
727 | +/* Sets a flag in a port status register but only set it if the port is | ||
728 | + * connected, if not set ConnectStatusChange flag. If flag is enabled | ||
729 | + * return 1. | ||
730 | + */ | ||
731 | +static int ohci_port_set_if_connected(OHCIState *ohci, int i, uint32_t val) | ||
732 | +{ | ||
733 | + int ret = 1; | ||
734 | + | ||
735 | + /* writing a 0 has no effect */ | ||
736 | + if (val == 0) | ||
737 | + return 0; | ||
738 | + | ||
739 | + /* If CurrentConnectStatus is cleared we set | ||
740 | + * ConnectStatusChange | ||
741 | + */ | ||
742 | + if (!(ohci->rhport[i].ctrl & OHCI_PORT_CCS)) { | ||
743 | + ohci->rhport[i].ctrl |= OHCI_PORT_CSC; | ||
744 | + if (ohci->rhstatus & OHCI_RHS_DRWE) { | ||
745 | + /* TODO: CSC is a wakeup event */ | ||
746 | + } | ||
747 | + return 0; | ||
748 | + } | ||
749 | + | ||
750 | + if (ohci->rhport[i].ctrl & val) | ||
751 | + ret = 0; | ||
752 | + | ||
753 | + /* set the bit */ | ||
754 | + ohci->rhport[i].ctrl |= val; | ||
755 | + | ||
756 | + return ret; | ||
757 | +} | ||
758 | + | ||
759 | +/* Set the frame interval - frame interval toggle is manipulated by the hcd only */ | ||
760 | +static void ohci_set_frame_interval(OHCIState *ohci, uint16_t val) | ||
761 | +{ | ||
762 | + val &= OHCI_FMI_FI; | ||
763 | + | ||
764 | + if (val != ohci->fi) { | ||
765 | + dprintf("usb-ohci: %s: FrameInterval = 0x%x (%u)\n", | ||
766 | + ohci->pci_dev.name, ohci->fi, ohci->fi); | ||
767 | + } | ||
768 | + | ||
769 | + ohci->fi = val; | ||
770 | +} | ||
771 | + | ||
772 | +static void ohci_port_power(OHCIState *ohci, int i, int p) | ||
773 | +{ | ||
774 | + if (p) { | ||
775 | + ohci->rhport[i].ctrl |= OHCI_PORT_PPS; | ||
776 | + } else { | ||
777 | + ohci->rhport[i].ctrl &= ~(OHCI_PORT_PPS| | ||
778 | + OHCI_PORT_CCS| | ||
779 | + OHCI_PORT_PSS| | ||
780 | + OHCI_PORT_PRS); | ||
781 | + } | ||
782 | +} | ||
783 | + | ||
784 | +/* Set HcControlRegister */ | ||
785 | +static void ohci_set_ctl(OHCIState *ohci, uint32_t val) | ||
786 | +{ | ||
787 | + uint32_t old_state; | ||
788 | + uint32_t new_state; | ||
789 | + | ||
790 | + old_state = ohci->ctl & OHCI_CTL_HCFS; | ||
791 | + ohci->ctl = val; | ||
792 | + new_state = ohci->ctl & OHCI_CTL_HCFS; | ||
793 | + | ||
794 | + /* no state change */ | ||
795 | + if (old_state == new_state) | ||
796 | + return; | ||
797 | + | ||
798 | + switch (new_state) { | ||
799 | + case OHCI_USB_OPERATIONAL: | ||
800 | + ohci_bus_start(ohci); | ||
801 | + break; | ||
802 | + case OHCI_USB_SUSPEND: | ||
803 | + ohci_bus_stop(ohci); | ||
804 | + dprintf("usb-ohci: %s: USB Suspended\n", ohci->pci_dev.name); | ||
805 | + break; | ||
806 | + case OHCI_USB_RESUME: | ||
807 | + dprintf("usb-ohci: %s: USB Resume\n", ohci->pci_dev.name); | ||
808 | + break; | ||
809 | + case OHCI_USB_RESET: | ||
810 | + dprintf("usb-ohci: %s: USB Reset\n", ohci->pci_dev.name); | ||
811 | + break; | ||
812 | + } | ||
813 | +} | ||
814 | + | ||
815 | +static uint32_t ohci_get_frame_remaining(OHCIState *ohci) | ||
816 | +{ | ||
817 | + uint16_t fr; | ||
818 | + int64_t tks; | ||
819 | + | ||
820 | + if ((ohci->ctl & OHCI_CTL_HCFS) != OHCI_USB_OPERATIONAL) | ||
821 | + return (ohci->frt << 31); | ||
822 | + | ||
823 | + /* Being in USB operational state guarnatees sof_time was | ||
824 | + * set already. | ||
825 | + */ | ||
826 | + tks = qemu_get_clock(vm_clock) - ohci->sof_time; | ||
827 | + | ||
828 | + /* avoid muldiv if possible */ | ||
829 | + if (tks >= usb_frame_time) | ||
830 | + return (ohci->frt << 31); | ||
831 | + | ||
832 | + tks = muldiv64(1, tks, usb_bit_time); | ||
833 | + fr = (uint16_t)(ohci->fi - tks); | ||
834 | + | ||
835 | + return (ohci->frt << 31) | fr; | ||
836 | +} | ||
837 | + | ||
838 | + | ||
839 | +/* Set root hub status */ | ||
840 | +static void ohci_set_hub_status(OHCIState *ohci, uint32_t val) | ||
841 | +{ | ||
842 | + uint32_t old_state; | ||
843 | + | ||
844 | + old_state = ohci->rhstatus; | ||
845 | + | ||
846 | + /* write 1 to clear OCIC */ | ||
847 | + if (val & OHCI_RHS_OCIC) | ||
848 | + ohci->rhstatus &= ~OHCI_RHS_OCIC; | ||
849 | + | ||
850 | + if (val & OHCI_RHS_LPS) { | ||
851 | + int i; | ||
852 | + | ||
853 | + for (i = 0; i < ohci->num_ports; i++) | ||
854 | + ohci_port_power(ohci, i, 0); | ||
855 | + dprintf("usb-ohci: powered down all ports\n"); | ||
856 | + } | ||
857 | + | ||
858 | + if (val & OHCI_RHS_LPSC) { | ||
859 | + int i; | ||
860 | + | ||
861 | + for (i = 0; i < ohci->num_ports; i++) | ||
862 | + ohci_port_power(ohci, i, 1); | ||
863 | + dprintf("usb-ohci: powered up all ports\n"); | ||
864 | + } | ||
865 | + | ||
866 | + if (val & OHCI_RHS_DRWE) | ||
867 | + ohci->rhstatus |= OHCI_RHS_DRWE; | ||
868 | + | ||
869 | + if (val & OHCI_RHS_CRWE) | ||
870 | + ohci->rhstatus &= ~OHCI_RHS_DRWE; | ||
871 | + | ||
872 | + if (old_state != ohci->rhstatus) | ||
873 | + ohci_set_interrupt(ohci, OHCI_INTR_RHSC); | ||
874 | +} | ||
875 | + | ||
876 | +/* Set root hub port status */ | ||
877 | +static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val) | ||
878 | +{ | ||
879 | + uint32_t old_state; | ||
880 | + OHCIPort *port; | ||
881 | + | ||
882 | + port = &ohci->rhport[portnum]; | ||
883 | + old_state = port->ctrl; | ||
884 | + | ||
885 | + /* Write to clear CSC, PESC, PSSC, OCIC, PRSC */ | ||
886 | + if (val & OHCI_PORT_WTC) | ||
887 | + port->ctrl &= ~(val & OHCI_PORT_WTC); | ||
888 | + | ||
889 | + if (val & OHCI_PORT_CCS) | ||
890 | + port->ctrl &= ~OHCI_PORT_PES; | ||
891 | + | ||
892 | + ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PES); | ||
893 | + | ||
894 | + if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PSS)) | ||
895 | + dprintf("usb-ohci: port %d: SUSPEND\n", portnum); | ||
896 | + | ||
897 | + if (ohci_port_set_if_connected(ohci, portnum, val & OHCI_PORT_PRS)) { | ||
898 | + dprintf("usb-ohci: port %d: RESET\n", portnum); | ||
899 | + port->port.dev->handle_packet(port->port.dev, USB_MSG_RESET, | ||
900 | + 0, 0, NULL, 0); | ||
901 | + port->ctrl &= ~OHCI_PORT_PRS; | ||
902 | + /* ??? Should this also set OHCI_PORT_PESC. */ | ||
903 | + port->ctrl |= OHCI_PORT_PES | OHCI_PORT_PRSC; | ||
904 | + } | ||
905 | + | ||
906 | + /* Invert order here to ensure in ambiguous case, device is | ||
907 | + * powered up... | ||
908 | + */ | ||
909 | + if (val & OHCI_PORT_LSDA) | ||
910 | + ohci_port_power(ohci, portnum, 0); | ||
911 | + if (val & OHCI_PORT_PPS) | ||
912 | + ohci_port_power(ohci, portnum, 1); | ||
913 | + | ||
914 | + if (old_state != port->ctrl) | ||
915 | + ohci_set_interrupt(ohci, OHCI_INTR_RHSC); | ||
916 | + | ||
917 | + return; | ||
918 | +} | ||
919 | + | ||
920 | +static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr) | ||
921 | +{ | ||
922 | + OHCIState *ohci = ptr; | ||
923 | + | ||
924 | + addr -= ohci->mem_base; | ||
925 | + | ||
926 | + /* Only aligned reads are allowed on OHCI */ | ||
927 | + if (addr & 3) { | ||
928 | + fprintf(stderr, "usb-ohci: Mis-aligned read\n"); | ||
929 | + return 0xffffffff; | ||
930 | + } | ||
931 | + | ||
932 | + if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { | ||
933 | + /* HcRhPortStatus */ | ||
934 | + return ohci->rhport[(addr - 0x54) >> 2].ctrl | OHCI_PORT_PPS; | ||
935 | + } | ||
936 | + | ||
937 | + switch (addr >> 2) { | ||
938 | + case 0: /* HcRevision */ | ||
939 | + return 0x10; | ||
940 | + | ||
941 | + case 1: /* HcControl */ | ||
942 | + return ohci->ctl; | ||
943 | + | ||
944 | + case 2: /* HcCommandStatus */ | ||
945 | + return ohci->status; | ||
946 | + | ||
947 | + case 3: /* HcInterruptStatus */ | ||
948 | + return ohci->intr_status; | ||
949 | + | ||
950 | + case 4: /* HcInterruptEnable */ | ||
951 | + case 5: /* HcInterruptDisable */ | ||
952 | + return ohci->intr; | ||
953 | + | ||
954 | + case 6: /* HcHCCA */ | ||
955 | + return ohci->hcca; | ||
956 | + | ||
957 | + case 7: /* HcPeriodCurrentED */ | ||
958 | + return ohci->per_cur; | ||
959 | + | ||
960 | + case 8: /* HcControlHeadED */ | ||
961 | + return ohci->ctrl_head; | ||
962 | + | ||
963 | + case 9: /* HcControlCurrentED */ | ||
964 | + return ohci->ctrl_cur; | ||
965 | + | ||
966 | + case 10: /* HcBulkHeadED */ | ||
967 | + return ohci->bulk_head; | ||
968 | + | ||
969 | + case 11: /* HcBulkCurrentED */ | ||
970 | + return ohci->bulk_cur; | ||
971 | + | ||
972 | + case 12: /* HcDoneHead */ | ||
973 | + return ohci->done; | ||
974 | + | ||
975 | + case 13: /* HcFmInterval */ | ||
976 | + return (ohci->fit << 31) | (ohci->fsmps << 16) | (ohci->fi); | ||
977 | + | ||
978 | + case 14: /* HcFmRemaining */ | ||
979 | + return ohci_get_frame_remaining(ohci); | ||
980 | + | ||
981 | + case 15: /* HcFmNumber */ | ||
982 | + return ohci->frame_number; | ||
983 | + | ||
984 | + case 16: /* HcPeriodicStart */ | ||
985 | + return ohci->pstart; | ||
986 | + | ||
987 | + case 17: /* HcLSThreshold */ | ||
988 | + return ohci->lst; | ||
989 | + | ||
990 | + case 18: /* HcRhDescriptorA */ | ||
991 | + return ohci->rhdesc_a; | ||
992 | + | ||
993 | + case 19: /* HcRhDescriptorB */ | ||
994 | + return ohci->rhdesc_b; | ||
995 | + | ||
996 | + case 20: /* HcRhStatus */ | ||
997 | + return ohci->rhstatus; | ||
998 | + | ||
999 | + default: | ||
1000 | + fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr); | ||
1001 | + return 0xffffffff; | ||
1002 | + } | ||
1003 | +} | ||
1004 | + | ||
1005 | +static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val) | ||
1006 | +{ | ||
1007 | + OHCIState *ohci = ptr; | ||
1008 | + | ||
1009 | + addr -= ohci->mem_base; | ||
1010 | + | ||
1011 | + /* Only aligned reads are allowed on OHCI */ | ||
1012 | + if (addr & 3) { | ||
1013 | + fprintf(stderr, "usb-ohci: Mis-aligned write\n"); | ||
1014 | + return; | ||
1015 | + } | ||
1016 | + | ||
1017 | + if (addr >= 0x54 && addr < 0x54 + ohci->num_ports * 4) { | ||
1018 | + /* HcRhPortStatus */ | ||
1019 | + ohci_port_set_status(ohci, (addr - 0x54) >> 2, val); | ||
1020 | + return; | ||
1021 | + } | ||
1022 | + | ||
1023 | + switch (addr >> 2) { | ||
1024 | + case 1: /* HcControl */ | ||
1025 | + ohci_set_ctl(ohci, val); | ||
1026 | + break; | ||
1027 | + | ||
1028 | + case 2: /* HcCommandStatus */ | ||
1029 | + /* SOC is read-only */ | ||
1030 | + val = (val & ~OHCI_STATUS_SOC); | ||
1031 | + | ||
1032 | + /* Bits written as '0' remain unchanged in the register */ | ||
1033 | + ohci->status |= val; | ||
1034 | + | ||
1035 | + if (ohci->status & OHCI_STATUS_HCR) | ||
1036 | + ohci_reset(ohci); | ||
1037 | + break; | ||
1038 | + | ||
1039 | + case 3: /* HcInterruptStatus */ | ||
1040 | + ohci->intr_status &= ~val; | ||
1041 | + ohci_intr_update(ohci); | ||
1042 | + break; | ||
1043 | + | ||
1044 | + case 4: /* HcInterruptEnable */ | ||
1045 | + ohci->intr |= val; | ||
1046 | + ohci_intr_update(ohci); | ||
1047 | + break; | ||
1048 | + | ||
1049 | + case 5: /* HcInterruptDisable */ | ||
1050 | + ohci->intr &= ~val; | ||
1051 | + ohci_intr_update(ohci); | ||
1052 | + break; | ||
1053 | + | ||
1054 | + case 6: /* HcHCCA */ | ||
1055 | + ohci->hcca = val & OHCI_HCCA_MASK; | ||
1056 | + break; | ||
1057 | + | ||
1058 | + case 8: /* HcControlHeadED */ | ||
1059 | + ohci->ctrl_head = val & OHCI_EDPTR_MASK; | ||
1060 | + break; | ||
1061 | + | ||
1062 | + case 9: /* HcControlCurrentED */ | ||
1063 | + ohci->ctrl_cur = val & OHCI_EDPTR_MASK; | ||
1064 | + break; | ||
1065 | + | ||
1066 | + case 10: /* HcBulkHeadED */ | ||
1067 | + ohci->bulk_head = val & OHCI_EDPTR_MASK; | ||
1068 | + break; | ||
1069 | + | ||
1070 | + case 11: /* HcBulkCurrentED */ | ||
1071 | + ohci->bulk_cur = val & OHCI_EDPTR_MASK; | ||
1072 | + break; | ||
1073 | + | ||
1074 | + case 13: /* HcFmInterval */ | ||
1075 | + ohci->fsmps = (val & OHCI_FMI_FSMPS) >> 16; | ||
1076 | + ohci->fit = (val & OHCI_FMI_FIT) >> 31; | ||
1077 | + ohci_set_frame_interval(ohci, val); | ||
1078 | + break; | ||
1079 | + | ||
1080 | + case 16: /* HcPeriodicStart */ | ||
1081 | + ohci->pstart = val & 0xffff; | ||
1082 | + break; | ||
1083 | + | ||
1084 | + case 17: /* HcLSThreshold */ | ||
1085 | + ohci->lst = val & 0xffff; | ||
1086 | + break; | ||
1087 | + | ||
1088 | + case 18: /* HcRhDescriptorA */ | ||
1089 | + ohci->rhdesc_a &= ~OHCI_RHA_RW_MASK; | ||
1090 | + ohci->rhdesc_a |= val & OHCI_RHA_RW_MASK; | ||
1091 | + break; | ||
1092 | + | ||
1093 | + case 19: /* HcRhDescriptorB */ | ||
1094 | + break; | ||
1095 | + | ||
1096 | + case 20: /* HcRhStatus */ | ||
1097 | + ohci_set_hub_status(ohci, val); | ||
1098 | + break; | ||
1099 | + | ||
1100 | + default: | ||
1101 | + fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr); | ||
1102 | + break; | ||
1103 | + } | ||
1104 | +} | ||
1105 | + | ||
1106 | +/* Only dword reads are defined on OHCI register space */ | ||
1107 | +static CPUReadMemoryFunc *ohci_readfn[3]={ | ||
1108 | + ohci_mem_read, | ||
1109 | + ohci_mem_read, | ||
1110 | + ohci_mem_read | ||
1111 | +}; | ||
1112 | + | ||
1113 | +/* Only dword writes are defined on OHCI register space */ | ||
1114 | +static CPUWriteMemoryFunc *ohci_writefn[3]={ | ||
1115 | + ohci_mem_write, | ||
1116 | + ohci_mem_write, | ||
1117 | + ohci_mem_write | ||
1118 | +}; | ||
1119 | + | ||
1120 | +static void ohci_mapfunc(PCIDevice *pci_dev, int i, | ||
1121 | + uint32_t addr, uint32_t size, int type) | ||
1122 | +{ | ||
1123 | + OHCIState *ohci = (OHCIState *)pci_dev; | ||
1124 | + ohci->mem_base = addr; | ||
1125 | + cpu_register_physical_memory(addr, size, ohci->mem); | ||
1126 | +} | ||
1127 | + | ||
1128 | +void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn) | ||
1129 | +{ | ||
1130 | + OHCIState *ohci; | ||
1131 | + int vid = 0x106b; | ||
1132 | + int did = 0x003f; | ||
1133 | + int i; | ||
1134 | + | ||
1135 | + | ||
1136 | + if (usb_frame_time == 0) { | ||
1137 | +#if OHCI_TIME_WARP | ||
1138 | + usb_frame_time = ticks_per_sec; | ||
1139 | + usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ/1000); | ||
1140 | +#else | ||
1141 | + usb_frame_time = muldiv64(1, ticks_per_sec, 1000); | ||
1142 | + if (ticks_per_sec >= USB_HZ) { | ||
1143 | + usb_bit_time = muldiv64(1, ticks_per_sec, USB_HZ); | ||
1144 | + } else { | ||
1145 | + usb_bit_time = 1; | ||
1146 | + } | ||
1147 | +#endif | ||
1148 | + dprintf("usb-ohci: usb_bit_time=%lli usb_frame_time=%lli\n", | ||
1149 | + usb_frame_time, usb_bit_time); | ||
1150 | + } | ||
1151 | + | ||
1152 | + ohci = (OHCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci), | ||
1153 | + devfn, NULL, NULL); | ||
1154 | + if (ohci == NULL) { | ||
1155 | + fprintf(stderr, "usb-ohci: Failed to register PCI device\n"); | ||
1156 | + return; | ||
1157 | + } | ||
1158 | + | ||
1159 | + ohci->pci_dev.config[0x00] = vid & 0xff; | ||
1160 | + ohci->pci_dev.config[0x01] = (vid >> 8) & 0xff; | ||
1161 | + ohci->pci_dev.config[0x02] = did & 0xff; | ||
1162 | + ohci->pci_dev.config[0x03] = (did >> 8) & 0xff; | ||
1163 | + ohci->pci_dev.config[0x09] = 0x10; /* OHCI */ | ||
1164 | + ohci->pci_dev.config[0x0a] = 0x3; | ||
1165 | + ohci->pci_dev.config[0x0b] = 0xc; | ||
1166 | + ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */ | ||
1167 | + | ||
1168 | + ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci); | ||
1169 | + | ||
1170 | + pci_register_io_region((struct PCIDevice *)ohci, 0, 256, | ||
1171 | + PCI_ADDRESS_SPACE_MEM, ohci_mapfunc); | ||
1172 | + | ||
1173 | + ohci->num_ports = num_ports; | ||
1174 | + for (i = 0; i < num_ports; i++) { | ||
1175 | + qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach); | ||
1176 | + } | ||
1177 | + | ||
1178 | + ohci_reset(ohci); | ||
1179 | +} |
hw/usb-uhci.c
@@ -638,11 +638,10 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, | @@ -638,11 +638,10 @@ static void uhci_map(PCIDevice *pci_dev, int region_num, | ||
638 | register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); | 638 | register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); |
639 | } | 639 | } |
640 | 640 | ||
641 | -void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn) | 641 | +void usb_uhci_init(PCIBus *bus, int devfn) |
642 | { | 642 | { |
643 | UHCIState *s; | 643 | UHCIState *s; |
644 | uint8_t *pci_conf; | 644 | uint8_t *pci_conf; |
645 | - UHCIPort *port; | ||
646 | int i; | 645 | int i; |
647 | 646 | ||
648 | s = (UHCIState *)pci_register_device(bus, | 647 | s = (UHCIState *)pci_register_device(bus, |
@@ -662,11 +661,7 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn) | @@ -662,11 +661,7 @@ void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn) | ||
662 | pci_conf[0x60] = 0x10; // release number | 661 | pci_conf[0x60] = 0x10; // release number |
663 | 662 | ||
664 | for(i = 0; i < NB_PORTS; i++) { | 663 | for(i = 0; i < NB_PORTS; i++) { |
665 | - port = &s->ports[i]; | ||
666 | - port->port.opaque = s; | ||
667 | - port->port.index = i; | ||
668 | - port->port.attach = uhci_attach; | ||
669 | - usb_ports[i] = &port->port; | 664 | + qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach); |
670 | } | 665 | } |
671 | s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); | 666 | s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); |
672 | 667 |
hw/usb.h
@@ -137,12 +137,15 @@ struct USBDevice { | @@ -137,12 +137,15 @@ struct USBDevice { | ||
137 | int setup_index; | 137 | int setup_index; |
138 | }; | 138 | }; |
139 | 139 | ||
140 | +typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev); | ||
141 | + | ||
140 | /* USB port on which a device can be connected */ | 142 | /* USB port on which a device can be connected */ |
141 | struct USBPort { | 143 | struct USBPort { |
142 | USBDevice *dev; | 144 | USBDevice *dev; |
143 | - void (*attach)(USBPort *port, USBDevice *dev); | 145 | + usb_attachfn attach; |
144 | void *opaque; | 146 | void *opaque; |
145 | int index; /* internal port index, may be used with the opaque */ | 147 | int index; /* internal port index, may be used with the opaque */ |
148 | + struct USBPort *next; /* Used internally by qemu. */ | ||
146 | }; | 149 | }; |
147 | 150 | ||
148 | void usb_attach(USBPort *port, USBDevice *dev); | 151 | void usb_attach(USBPort *port, USBDevice *dev); |
@@ -152,10 +155,13 @@ int usb_generic_handle_packet(USBDevice *s, int pid, | @@ -152,10 +155,13 @@ int usb_generic_handle_packet(USBDevice *s, int pid, | ||
152 | int set_usb_string(uint8_t *buf, const char *str); | 155 | int set_usb_string(uint8_t *buf, const char *str); |
153 | 156 | ||
154 | /* usb hub */ | 157 | /* usb hub */ |
155 | -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports); | 158 | +USBDevice *usb_hub_init(int nb_ports); |
156 | 159 | ||
157 | /* usb-uhci.c */ | 160 | /* usb-uhci.c */ |
158 | -void usb_uhci_init(PCIBus *bus, USBPort **usb_ports, int devfn); | 161 | +void usb_uhci_init(PCIBus *bus, int devfn); |
162 | + | ||
163 | +/* usb-ohci.c */ | ||
164 | +void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn); | ||
159 | 165 | ||
160 | /* usb-linux.c */ | 166 | /* usb-linux.c */ |
161 | USBDevice *usb_host_device_open(const char *devname); | 167 | USBDevice *usb_host_device_open(const char *devname); |
hw/versatilepb.c
@@ -374,6 +374,9 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, | @@ -374,6 +374,9 @@ static void versatile_init(int ram_size, int vga_ram_size, int boot_device, | ||
374 | pci_nic_init(pci_bus, nd); | 374 | pci_nic_init(pci_bus, nd); |
375 | } | 375 | } |
376 | } | 376 | } |
377 | + if (usb_enabled) { | ||
378 | + usb_ohci_init(pci_bus, 3, -1); | ||
379 | + } | ||
377 | 380 | ||
378 | pl011_init(0x101f1000, pic, 12, serial_hds[0]); | 381 | pl011_init(0x101f1000, pic, 12, serial_hds[0]); |
379 | pl011_init(0x101f2000, pic, 13, serial_hds[1]); | 382 | pl011_init(0x101f2000, pic, 13, serial_hds[1]); |
vl.c
@@ -106,6 +106,9 @@ | @@ -106,6 +106,9 @@ | ||
106 | /* in ms */ | 106 | /* in ms */ |
107 | #define GUI_REFRESH_INTERVAL 30 | 107 | #define GUI_REFRESH_INTERVAL 30 |
108 | 108 | ||
109 | +/* Max number of USB devices that can be specified on the commandline. */ | ||
110 | +#define MAX_USB_CMDLINE 8 | ||
111 | + | ||
109 | /* XXX: use a two level table to limit memory usage */ | 112 | /* XXX: use a two level table to limit memory usage */ |
110 | #define MAX_IOPORTS 65536 | 113 | #define MAX_IOPORTS 65536 |
111 | 114 | ||
@@ -145,8 +148,6 @@ CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; | @@ -145,8 +148,6 @@ CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; | ||
145 | int win2k_install_hack = 0; | 148 | int win2k_install_hack = 0; |
146 | #endif | 149 | #endif |
147 | int usb_enabled = 0; | 150 | int usb_enabled = 0; |
148 | -USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; | ||
149 | -USBDevice *vm_usb_hub; | ||
150 | static VLANState *first_vlan; | 151 | static VLANState *first_vlan; |
151 | int smp_cpus = 1; | 152 | int smp_cpus = 1; |
152 | int vnc_display = -1; | 153 | int vnc_display = -1; |
@@ -3249,47 +3250,71 @@ void do_info_network(void) | @@ -3249,47 +3250,71 @@ void do_info_network(void) | ||
3249 | /***********************************************************/ | 3250 | /***********************************************************/ |
3250 | /* USB devices */ | 3251 | /* USB devices */ |
3251 | 3252 | ||
3253 | +static USBPort *used_usb_ports; | ||
3254 | +static USBPort *free_usb_ports; | ||
3255 | + | ||
3256 | +/* ??? Maybe change this to register a hub to keep track of the topology. */ | ||
3257 | +void qemu_register_usb_port(USBPort *port, void *opaque, int index, | ||
3258 | + usb_attachfn attach) | ||
3259 | +{ | ||
3260 | + port->opaque = opaque; | ||
3261 | + port->index = index; | ||
3262 | + port->attach = attach; | ||
3263 | + port->next = free_usb_ports; | ||
3264 | + free_usb_ports = port; | ||
3265 | +} | ||
3266 | + | ||
3252 | static int usb_device_add(const char *devname) | 3267 | static int usb_device_add(const char *devname) |
3253 | { | 3268 | { |
3254 | const char *p; | 3269 | const char *p; |
3255 | USBDevice *dev; | 3270 | USBDevice *dev; |
3256 | - int i; | 3271 | + USBPort *port; |
3257 | 3272 | ||
3258 | - if (!vm_usb_hub) | ||
3259 | - return -1; | ||
3260 | - for(i = 0;i < MAX_VM_USB_PORTS; i++) { | ||
3261 | - if (!vm_usb_ports[i]->dev) | ||
3262 | - break; | ||
3263 | - } | ||
3264 | - if (i == MAX_VM_USB_PORTS) | 3273 | + if (!free_usb_ports) |
3265 | return -1; | 3274 | return -1; |
3266 | 3275 | ||
3267 | if (strstart(devname, "host:", &p)) { | 3276 | if (strstart(devname, "host:", &p)) { |
3268 | dev = usb_host_device_open(p); | 3277 | dev = usb_host_device_open(p); |
3269 | - if (!dev) | ||
3270 | - return -1; | ||
3271 | } else if (!strcmp(devname, "mouse")) { | 3278 | } else if (!strcmp(devname, "mouse")) { |
3272 | dev = usb_mouse_init(); | 3279 | dev = usb_mouse_init(); |
3273 | - if (!dev) | ||
3274 | - return -1; | ||
3275 | } else if (!strcmp(devname, "tablet")) { | 3280 | } else if (!strcmp(devname, "tablet")) { |
3276 | dev = usb_tablet_init(); | 3281 | dev = usb_tablet_init(); |
3277 | - if (!dev) | ||
3278 | - return -1; | ||
3279 | } else { | 3282 | } else { |
3280 | return -1; | 3283 | return -1; |
3281 | } | 3284 | } |
3282 | - usb_attach(vm_usb_ports[i], dev); | 3285 | + if (!dev) |
3286 | + return -1; | ||
3287 | + | ||
3288 | + /* Find a USB port to add the device to. */ | ||
3289 | + port = free_usb_ports; | ||
3290 | + if (!port->next) { | ||
3291 | + USBDevice *hub; | ||
3292 | + | ||
3293 | + /* Create a new hub and chain it on. */ | ||
3294 | + free_usb_ports = NULL; | ||
3295 | + port->next = used_usb_ports; | ||
3296 | + used_usb_ports = port; | ||
3297 | + | ||
3298 | + hub = usb_hub_init(VM_USB_HUB_SIZE); | ||
3299 | + usb_attach(port, hub); | ||
3300 | + port = free_usb_ports; | ||
3301 | + } | ||
3302 | + | ||
3303 | + free_usb_ports = port->next; | ||
3304 | + port->next = used_usb_ports; | ||
3305 | + used_usb_ports = port; | ||
3306 | + usb_attach(port, dev); | ||
3283 | return 0; | 3307 | return 0; |
3284 | } | 3308 | } |
3285 | 3309 | ||
3286 | static int usb_device_del(const char *devname) | 3310 | static int usb_device_del(const char *devname) |
3287 | { | 3311 | { |
3288 | - USBDevice *dev; | ||
3289 | - int bus_num, addr, i; | 3312 | + USBPort *port; |
3313 | + USBPort **lastp; | ||
3314 | + int bus_num, addr; | ||
3290 | const char *p; | 3315 | const char *p; |
3291 | 3316 | ||
3292 | - if (!vm_usb_hub) | 3317 | + if (!used_usb_ports) |
3293 | return -1; | 3318 | return -1; |
3294 | 3319 | ||
3295 | p = strchr(devname, '.'); | 3320 | p = strchr(devname, '.'); |
@@ -3299,14 +3324,21 @@ static int usb_device_del(const char *devname) | @@ -3299,14 +3324,21 @@ static int usb_device_del(const char *devname) | ||
3299 | addr = strtoul(p + 1, NULL, 0); | 3324 | addr = strtoul(p + 1, NULL, 0); |
3300 | if (bus_num != 0) | 3325 | if (bus_num != 0) |
3301 | return -1; | 3326 | return -1; |
3302 | - for(i = 0;i < MAX_VM_USB_PORTS; i++) { | ||
3303 | - dev = vm_usb_ports[i]->dev; | ||
3304 | - if (dev && dev->addr == addr) | ||
3305 | - break; | 3327 | + |
3328 | + lastp = &used_usb_ports; | ||
3329 | + port = used_usb_ports; | ||
3330 | + while (port && port->dev->addr != addr) { | ||
3331 | + lastp = &port->next; | ||
3332 | + port = port->next; | ||
3306 | } | 3333 | } |
3307 | - if (i == MAX_VM_USB_PORTS) | 3334 | + |
3335 | + if (!port) | ||
3308 | return -1; | 3336 | return -1; |
3309 | - usb_attach(vm_usb_ports[i], NULL); | 3337 | + |
3338 | + *lastp = port->next; | ||
3339 | + usb_attach(port, NULL); | ||
3340 | + port->next = free_usb_ports; | ||
3341 | + free_usb_ports = port; | ||
3310 | return 0; | 3342 | return 0; |
3311 | } | 3343 | } |
3312 | 3344 | ||
@@ -3329,35 +3361,34 @@ void do_usb_del(const char *devname) | @@ -3329,35 +3361,34 @@ void do_usb_del(const char *devname) | ||
3329 | void usb_info(void) | 3361 | void usb_info(void) |
3330 | { | 3362 | { |
3331 | USBDevice *dev; | 3363 | USBDevice *dev; |
3332 | - int i; | 3364 | + USBPort *port; |
3333 | const char *speed_str; | 3365 | const char *speed_str; |
3334 | 3366 | ||
3335 | - if (!vm_usb_hub) { | 3367 | + if (!usb_enabled) { |
3336 | term_printf("USB support not enabled\n"); | 3368 | term_printf("USB support not enabled\n"); |
3337 | return; | 3369 | return; |
3338 | } | 3370 | } |
3339 | 3371 | ||
3340 | - for(i = 0; i < MAX_VM_USB_PORTS; i++) { | ||
3341 | - dev = vm_usb_ports[i]->dev; | ||
3342 | - if (dev) { | ||
3343 | - term_printf("Hub port %d:\n", i); | ||
3344 | - switch(dev->speed) { | ||
3345 | - case USB_SPEED_LOW: | ||
3346 | - speed_str = "1.5"; | ||
3347 | - break; | ||
3348 | - case USB_SPEED_FULL: | ||
3349 | - speed_str = "12"; | ||
3350 | - break; | ||
3351 | - case USB_SPEED_HIGH: | ||
3352 | - speed_str = "480"; | ||
3353 | - break; | ||
3354 | - default: | ||
3355 | - speed_str = "?"; | ||
3356 | - break; | ||
3357 | - } | ||
3358 | - term_printf(" Device %d.%d, speed %s Mb/s\n", | ||
3359 | - 0, dev->addr, speed_str); | 3372 | + for (port = used_usb_ports; port; port = port->next) { |
3373 | + dev = port->dev; | ||
3374 | + if (!dev) | ||
3375 | + continue; | ||
3376 | + switch(dev->speed) { | ||
3377 | + case USB_SPEED_LOW: | ||
3378 | + speed_str = "1.5"; | ||
3379 | + break; | ||
3380 | + case USB_SPEED_FULL: | ||
3381 | + speed_str = "12"; | ||
3382 | + break; | ||
3383 | + case USB_SPEED_HIGH: | ||
3384 | + speed_str = "480"; | ||
3385 | + break; | ||
3386 | + default: | ||
3387 | + speed_str = "?"; | ||
3388 | + break; | ||
3360 | } | 3389 | } |
3390 | + term_printf(" Device %d.%d, speed %s Mb/s\n", | ||
3391 | + 0, dev->addr, speed_str); | ||
3361 | } | 3392 | } |
3362 | } | 3393 | } |
3363 | 3394 | ||
@@ -5066,7 +5097,7 @@ int main(int argc, char **argv) | @@ -5066,7 +5097,7 @@ int main(int argc, char **argv) | ||
5066 | int parallel_device_index; | 5097 | int parallel_device_index; |
5067 | const char *loadvm = NULL; | 5098 | const char *loadvm = NULL; |
5068 | QEMUMachine *machine; | 5099 | QEMUMachine *machine; |
5069 | - char usb_devices[MAX_VM_USB_PORTS][128]; | 5100 | + char usb_devices[MAX_USB_CMDLINE][128]; |
5070 | int usb_devices_index; | 5101 | int usb_devices_index; |
5071 | 5102 | ||
5072 | LIST_INIT (&vm_change_state_head); | 5103 | LIST_INIT (&vm_change_state_head); |
@@ -5425,7 +5456,7 @@ int main(int argc, char **argv) | @@ -5425,7 +5456,7 @@ int main(int argc, char **argv) | ||
5425 | break; | 5456 | break; |
5426 | case QEMU_OPTION_usbdevice: | 5457 | case QEMU_OPTION_usbdevice: |
5427 | usb_enabled = 1; | 5458 | usb_enabled = 1; |
5428 | - if (usb_devices_index >= MAX_VM_USB_PORTS) { | 5459 | + if (usb_devices_index >= MAX_USB_CMDLINE) { |
5429 | fprintf(stderr, "Too many USB devices\n"); | 5460 | fprintf(stderr, "Too many USB devices\n"); |
5430 | exit(1); | 5461 | exit(1); |
5431 | } | 5462 | } |
@@ -5596,17 +5627,6 @@ int main(int argc, char **argv) | @@ -5596,17 +5627,6 @@ int main(int argc, char **argv) | ||
5596 | } | 5627 | } |
5597 | } | 5628 | } |
5598 | 5629 | ||
5599 | - /* init USB devices */ | ||
5600 | - if (usb_enabled) { | ||
5601 | - vm_usb_hub = usb_hub_init(vm_usb_ports, MAX_VM_USB_PORTS); | ||
5602 | - for(i = 0; i < usb_devices_index; i++) { | ||
5603 | - if (usb_device_add(usb_devices[i]) < 0) { | ||
5604 | - fprintf(stderr, "Warning: could not add USB device %s\n", | ||
5605 | - usb_devices[i]); | ||
5606 | - } | ||
5607 | - } | ||
5608 | - } | ||
5609 | - | ||
5610 | register_savevm("timer", 0, 1, timer_save, timer_load, NULL); | 5630 | register_savevm("timer", 0, 1, timer_save, timer_load, NULL); |
5611 | register_savevm("ram", 0, 1, ram_save, ram_load, NULL); | 5631 | register_savevm("ram", 0, 1, ram_save, ram_load, NULL); |
5612 | 5632 | ||
@@ -5710,6 +5730,16 @@ int main(int argc, char **argv) | @@ -5710,6 +5730,16 @@ int main(int argc, char **argv) | ||
5710 | ds, fd_filename, snapshot, | 5730 | ds, fd_filename, snapshot, |
5711 | kernel_filename, kernel_cmdline, initrd_filename); | 5731 | kernel_filename, kernel_cmdline, initrd_filename); |
5712 | 5732 | ||
5733 | + /* init USB devices */ | ||
5734 | + if (usb_enabled) { | ||
5735 | + for(i = 0; i < usb_devices_index; i++) { | ||
5736 | + if (usb_device_add(usb_devices[i]) < 0) { | ||
5737 | + fprintf(stderr, "Warning: could not add USB device %s\n", | ||
5738 | + usb_devices[i]); | ||
5739 | + } | ||
5740 | + } | ||
5741 | + } | ||
5742 | + | ||
5713 | gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); | 5743 | gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); |
5714 | qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); | 5744 | qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); |
5715 | 5745 |
vl.h
@@ -1022,10 +1022,10 @@ int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq); | @@ -1022,10 +1022,10 @@ int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq); | ||
1022 | 1022 | ||
1023 | /* usb ports of the VM */ | 1023 | /* usb ports of the VM */ |
1024 | 1024 | ||
1025 | -#define MAX_VM_USB_PORTS 8 | 1025 | +void qemu_register_usb_port(USBPort *port, void *opaque, int index, |
1026 | + usb_attachfn attach); | ||
1026 | 1027 | ||
1027 | -extern USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; | ||
1028 | -extern USBDevice *vm_usb_hub; | 1028 | +#define VM_USB_HUB_SIZE 8 |
1029 | 1029 | ||
1030 | void do_usb_add(const char *devname); | 1030 | void do_usb_add(const char *devname); |
1031 | void do_usb_del(const char *devname); | 1031 | void do_usb_del(const char *devname); |