/[pearpc]/src/io/usb/usb.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /src/io/usb/usb.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 11850 byte(s)
import upstream CVS
1 dpavlin 1 /*
2     * PearPC
3     * usb.cc
4     *
5     * Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
6     *
7     * References:
8     * [1] OpenHCI - Open Host Controller Interface Specification for USB
9     * Revision 1.0a - hcir1_0a.pdf
10     * [2] Linux USB ohci-driver
11     * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
12     * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
13     *
14     * This program is free software; you can redistribute it and/or modify
15     * it under the terms of the GNU General Public License version 2 as
16     * published by the Free Software Foundation.
17     *
18     * This program is distributed in the hope that it will be useful,
19     * but WITHOUT ANY WARRANTY; without even the implied warranty of
20     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21     * GNU General Public License for more details.
22     *
23     * You should have received a copy of the GNU General Public License
24     * along with this program; if not, write to the Free Software
25     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26     */
27    
28     #include "debug/tracers.h"
29     #include "system/arch/sysendian.h"
30     #include "io/pci/pci.h"
31     #include "usb.h"
32    
33     #include <cstring>
34    
35     #define NUM_INTS 32 /* part of the OHCI standard */
36     #define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */
37    
38     struct ohci_hcca {
39     uint32 int_table[NUM_INTS]; /* Interrupt ED table */
40     uint16 frame_no; /* current frame number */
41     uint16 pad1; /* set to 0 on each frame_no change */
42     uint32 done_head; /* info returned for an interrupt */
43     uint8 reserved_for_hc[116];
44     } PACKED;
45    
46     // [1].122
47     #define OHCI_REG_REVISION 0x00 // [1].123
48     #define OHCI_REG_CONTROL 0x04 // [1].123
49     #define OHCI_REG_CMDSTATUS 0x08 // [1].126
50     #define OHCI_REG_INTRSTATUS 0x0c // [1].126
51     #define OHCI_REG_INTRENABLE 0x10 // [1].126
52     #define OHCI_REG_INTRDISABLE 0x14 // [1].126
53     #define OHCI_REG_HCCA 0x18 // [1].126
54     #define OHCI_REG_ED_PERIODCUR 0x1c // [1].126
55     #define OHCI_REG_ED_CONTROL_HD 0x20 // [1].126
56     #define OHCI_REG_ED_CONTROL_CUR 0x24 // [1].126
57     #define OHCI_REG_ED_BULK_HD 0x28 // [1].126
58     #define OHCI_REG_ED_BULK_CUR 0x2c // [1].126
59     #define OHCI_REG_DONEHEAD 0x30 // [1].126
60     #define OHCI_REG_FMINTERVAL 0x34 // [1].126
61     #define OHCI_REG_FMREMAIN 0x38 // [1].126
62     #define OHCI_REG_FMNUMBER 0x3c // [1].126
63     #define OHCI_REG_PERIODICSTART 0x40 // [1].126
64     #define OHCI_REG_LSTHRESH 0x44 // [1].126
65     #define OHCI_REG_ROOTHUB_A 0x48
66     #define OHCI_REG_ROOTHUB_B 0x4c
67     #define OHCI_REG_ROOTHUB_STAT 0x50
68     #define OHCI_REG_ROOTHUB_PORTS 0x54
69    
70     /*
71     * bits in ohci_hcregs.control
72     */
73     #define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
74     #define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
75     #define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
76     #define OHCI_CTRL_CLE (1 << 4) /* control list enable */
77     #define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
78     #define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
79     #define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
80     #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
81     #define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
82    
83     /* pre-shifted values for HCFS */
84     # define OHCI_USB_RESET (0 << 6)
85     # define OHCI_USB_RESUME (1 << 6)
86     # define OHCI_USB_OPER (2 << 6)
87     # define OHCI_USB_SUSPEND (3 << 6)
88    
89     /*
90     * bits in ohci_hcregs.{intrstatus|intrenable|intrdisable}
91     */
92     #define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
93     #define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
94     #define OHCI_INTR_SF (1 << 2) /* start frame */
95     #define OHCI_INTR_RD (1 << 3) /* resume detect */
96     #define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
97     #define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
98     #define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
99     #define OHCI_INTR_OC (1 << 30) /* ownership change */
100     #define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
101    
102     /*
103     * bits in ohci_hcregs.cmdstatus
104     */
105     #define OHCI_HCR (1 << 0) /* host controller reset */
106     #define OHCI_CLF (1 << 1) /* control list filled */
107     #define OHCI_BLF (1 << 2) /* bulk list filled */
108     #define OHCI_OCR (1 << 3) /* ownership change request */
109     #define OHCI_SOC (3 << 16) /* scheduling overrun count */
110    
111     /*
112     * bits in ohci_hcregs.roothub.portstatus [1].142
113     */
114     #define OHCI_RH_PS_CCS (1 << 0) /* current connect status */
115     #define OHCI_RH_PS_PES (1 << 1) /* port enable status */
116     #define OHCI_RH_PS_PSS (1 << 2) /* port suspend status */
117     #define OHCI_RH_PS_POCI (1 << 3) /* port overrun current indicator */
118     #define OHCI_RH_PS_PRS (1 << 4) /* port reset status */
119     #define OHCI_RH_PS_PPS (1 << 8) /* port power status */
120     #define OHCI_RH_PS_LSDA (1 << 8) /* low speed device attached */
121     #define OHCI_RH_PS_CSC (1 << 16) /* connect status change */
122     #define OHCI_RH_PS_PESC (1 << 17) /* port enable status change */
123     #define OHCI_RH_PS_PSSC (1 << 18) /* port suspend status change */
124     #define OHCI_RH_PS_OCIC (1 << 19) /* overrun current indicator change */
125     #define OHCI_RH_PS_PRSC (1 << 20) /* port reset status change */
126    
127     struct ohci_hcregs {
128     /* control and status registers */
129     uint32 control;
130     uint32 cmdstatus;
131     uint32 intrstatus;
132     uint32 intrenable;
133     uint32 intrdisable;
134     /* memory pointers */
135     uint32 hcca;
136     uint32 ed_periodcurrent;
137     uint32 ed_controlhead;
138     uint32 ed_controlcurrent;
139     uint32 ed_bulkhead;
140     uint32 ed_bulkcurrent;
141     uint32 donehead;
142     /* frame counters */
143     uint32 fminterval;
144     uint32 fmremaining;
145     uint32 fmnumber;
146     uint32 periodicstart;
147     uint32 lsthresh;
148     /* Root hub ports */
149     struct ohci_roothub_regs {
150     uint32 a;
151     uint32 b;
152     uint32 status;
153     uint32 portstatus[MAX_ROOT_PORTS];
154     } roothub;
155     };
156    
157     static inline const char *hc_regname(uint32 a)
158     {
159     a >>= 2;
160     if (a > 20) return "unknown";
161     char *names[] = {"revision","control","cmdstatus","intrstatus","intrenable",
162     "intrdisable","hcca","ed_periodcurrent","ed_controlhead","ed_controlcurrent",
163     "ed_bulkhead","ed_bulkcurrent","donehead","fminterval","fmremaining",
164     "fmnumber","periodicstart", "lsthresh", "roothub.a", "roothub.b", "roothub.status"};
165     return names[a];
166     }
167    
168     extern bool gSinglestep;
169    
170     /*
171     *
172     */
173     class PCI_USB: public PCI_Device {
174     public:
175     ohci_hcregs hcregs;
176     uint rootport_count;
177    
178     PCI_USB()
179     :PCI_Device("pci-usb", 0x01, 0x06)
180     {
181     mIORegSize[0] = 0x1000;
182     mIORegType[0] = PCI_ADDRESS_SPACE_MEM;
183    
184     mConfig[0x00] = 0x45; // vendor ID
185     mConfig[0x01] = 0x10;
186     mConfig[0x02] = 0x61; // unit ID
187     mConfig[0x03] = 0xc8;
188    
189     mConfig[0x08] = 0x10; // revision
190     mConfig[0x09] = 0x10; //
191     mConfig[0x0a] = 0x03; //
192     mConfig[0x0b] = 0x0c; //
193    
194     mConfig[0x0e] = 0x00; // header-type
195    
196     assignMemAddress(0, 0x80881000);
197    
198     mConfig[0x3c] = 0x03;
199     mConfig[0x3d] = 0x03;
200     mConfig[0x3e] = 0x03;
201     mConfig[0x3f] = 0x03;
202    
203     rootport_count = 1;
204     reset();
205     }
206    
207     void reset()
208     {
209     memset(&hcregs, 0, sizeof hcregs);
210     hcregs.fminterval = 0x2edf; // [1].134
211     hcregs.lsthresh = 0x628; // [1].137
212     hcregs.roothub.a = 0 // [1].138
213     | (1<<12) // No overcurrent protection supported
214     | (0<<10) // always 0
215     | (1<<9) // Ports are always powered on when the HC is powered on
216     | (0<<8) // all ports are powered at the same time.
217     | rootport_count; // number of rootports
218     // hcregs.roothub.portstatus[0] = ;
219     }
220    
221     virtual bool readDeviceMem(uint r, uint32 address, uint32 &data, uint size)
222     {
223     if (r != 0) return false;
224     if (size != 4) return false;
225     IO_USB_TRACE("read(r=%d, a=%08x (%s), %d)\n", r, address, hc_regname(address), size);
226    
227     switch (address) {
228     case OHCI_REG_REVISION:
229     // [1].123
230     data = 0x10;
231     break;
232     case OHCI_REG_CONTROL:
233     data = hcregs.control;
234     break;
235     case OHCI_REG_CMDSTATUS:
236     data = hcregs.cmdstatus;
237     break;
238     case OHCI_REG_INTRSTATUS:
239     data = hcregs.intrstatus;
240     break;
241     case OHCI_REG_INTRENABLE:
242     data = hcregs.intrenable;
243     break;
244     case OHCI_REG_INTRDISABLE:
245     data = hcregs.intrdisable;
246     break;
247     case OHCI_REG_HCCA:
248     data = hcregs.hcca;
249     break;
250     case OHCI_REG_ED_PERIODCUR:
251     data = hcregs.ed_periodcurrent;
252     break;
253     case OHCI_REG_ED_CONTROL_HD:
254     data = hcregs.ed_controlhead;
255     break;
256     case OHCI_REG_ED_CONTROL_CUR:
257     data = hcregs.ed_controlcurrent;
258     break;
259     case OHCI_REG_ED_BULK_HD:
260     data = hcregs.ed_bulkhead;
261     break;
262     case OHCI_REG_ED_BULK_CUR:
263     data = hcregs.ed_bulkcurrent;
264     break;
265     case OHCI_REG_DONEHEAD:
266     data = hcregs.donehead;
267     break;
268     case OHCI_REG_FMINTERVAL:
269     data = hcregs.fminterval;
270     break;
271     case OHCI_REG_FMREMAIN:
272     data = hcregs.fmremaining;
273     break;
274     case OHCI_REG_FMNUMBER:
275     data = hcregs.fmnumber;
276     break;
277     case OHCI_REG_PERIODICSTART:
278     data = hcregs.periodicstart;
279     break;
280     case OHCI_REG_LSTHRESH:
281     data = hcregs.lsthresh;
282     break;
283     case OHCI_REG_ROOTHUB_A:
284     data = hcregs.roothub.a;
285     break;
286     case OHCI_REG_ROOTHUB_B:
287     data = hcregs.roothub.b;
288     break;
289     case OHCI_REG_ROOTHUB_STAT:
290     data = hcregs.roothub.status;
291     break;
292     default:
293     address -= OHCI_REG_ROOTHUB_PORTS;
294     address >>= 2;
295     if (address < rootport_count) {
296     data = hcregs.roothub.portstatus[address];
297     break;
298     }
299     return false;
300     }
301    
302     // gSinglestep = true;
303     return true;
304     }
305    
306     virtual bool writeDeviceMem(uint r, uint32 address, uint32 data, uint size)
307     {
308     if (r != 0) return false;
309     if (size != 4) return false;
310     IO_USB_TRACE("write(r=%d, a=%08x (%s), data=%08x, %d)\n", r, address, hc_regname(address), data, size);
311    
312     switch (address) {
313     case OHCI_REG_REVISION:
314     // [1].123
315     IO_USB_WARN("revision is read only.\n");
316     return true;
317     case OHCI_REG_CONTROL:
318     hcregs.control = data;
319     break;
320     case OHCI_REG_CMDSTATUS:
321     if (data & OHCI_HCR) {
322     reset();
323     return true;
324     }
325     hcregs.cmdstatus = data;
326     break;
327     case OHCI_REG_INTRSTATUS:
328     hcregs.intrstatus = data;
329     break;
330     case OHCI_REG_INTRENABLE:
331     hcregs.intrenable = data;
332     break;
333     case OHCI_REG_INTRDISABLE:
334     hcregs.intrdisable = data;
335     break;
336     case OHCI_REG_HCCA:
337     hcregs.hcca = data;
338     break;
339     case OHCI_REG_ED_PERIODCUR:
340     hcregs.ed_periodcurrent = data;
341     break;
342     case OHCI_REG_ED_CONTROL_HD:
343     hcregs.ed_controlhead = data;
344     break;
345     case OHCI_REG_ED_CONTROL_CUR:
346     hcregs.ed_controlcurrent = data;
347     break;
348     case OHCI_REG_ED_BULK_HD:
349     hcregs.ed_bulkhead = data;
350     break;
351     case OHCI_REG_ED_BULK_CUR:
352     hcregs.ed_bulkcurrent = data;
353     break;
354     case OHCI_REG_DONEHEAD:
355     hcregs.donehead = data;
356     break;
357     case OHCI_REG_FMINTERVAL:
358     hcregs.fminterval = data;
359     break;
360     case OHCI_REG_FMREMAIN:
361     hcregs.fmremaining = data;
362     break;
363     case OHCI_REG_FMNUMBER:
364     hcregs.fmnumber = data;
365     break;
366     case OHCI_REG_PERIODICSTART:
367     hcregs.periodicstart = data;
368     break;
369     case OHCI_REG_LSTHRESH:
370     hcregs.lsthresh = data;
371     break;
372     case OHCI_REG_ROOTHUB_A:
373     hcregs.roothub.a = data;
374     break;
375     case OHCI_REG_ROOTHUB_B:
376     hcregs.roothub.b = data;
377     break;
378     case OHCI_REG_ROOTHUB_STAT:
379     hcregs.roothub.status = data;
380     break;
381     default:
382     address -= OHCI_REG_ROOTHUB_PORTS;
383     address >>= 2;
384     if (address < rootport_count) {
385     if (data & OHCI_RH_PS_CCS) {
386     // writing 1 to CCS clears PES
387     hcregs.roothub.portstatus[address] &= ~OHCI_RH_PS_PES;
388     }
389    
390     // writing 1 to these bits clears them
391     hcregs.roothub.portstatus[address] &= ~(data &
392     (OHCI_RH_PS_CSC | OHCI_RH_PS_PESC | OHCI_RH_PS_PSSC
393     | OHCI_RH_PS_OCIC | OHCI_RH_PS_PRSC));
394    
395     // writing 1 to these bits set them only if CCS is set
396     uint32 p = data & OHCI_RH_PS_PES | OHCI_RH_PS_PSS | OHCI_RH_PS_PRS;
397     if (p) {
398     if (hcregs.roothub.portstatus[address] & OHCI_RH_PS_CCS) {
399     hcregs.roothub.portstatus[address] |= p;
400     } else {
401     // attempt to enable/suspend/reset disconnected port
402     hcregs.roothub.portstatus[address] |= OHCI_RH_PS_CSC;
403     }
404     }
405    
406     // we dont support power switching
407     hcregs.roothub.portstatus[address] |= OHCI_RH_PS_PPS;
408     break;
409     }
410     }
411    
412     // gSinglestep = true;
413     return true;
414     }
415    
416     };
417    
418    
419     #include "configparser.h"
420    
421     #define USB_KEY_INSTALLED "pci_usb_installed"
422    
423     void usb_init()
424     {
425     if (gConfig->getConfigInt(USB_KEY_INSTALLED)) {
426     gPCI_Devices->insert(new PCI_USB());
427     }
428     }
429    
430     void usb_done()
431     {
432     }
433    
434     void usb_init_config()
435     {
436     gConfig->acceptConfigEntryIntDef(USB_KEY_INSTALLED, 0);
437     }

  ViewVC Help
Powered by ViewVC 1.1.26