5 * Copyright (C) 2009 Pawel Dziepak
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 //#include "manes/cds/
27 #include "manes/manec.h"
28 #include "manes/cds/root.h"
30 #include "arch/low/lowlevel.h"
32 #include "arch/low/hlt.h"
33 #include "manes/error.h"
34 #include "services/interrupt_manager.h"
36 using namespace resources
;
40 bool uhci::init_device(p
<did
> id
) {
41 p
<pci_did
> pid
= id
.cast
<pci_did
>();
51 manes::manec::get()->get_root()->new_component(manes::cds::component_name::from_path("/type,usb")).cast
<bus
>()->init_bus(this);
57 bool uhci::check_device(p
<did
> id
) {
58 p
<pci_did
> pid
= id
.cast
<pci_did
>();
63 int devclass
= pid
->get_bus().cast
<pci
>()->get_devclass(id
);
64 if (devclass
!= 0x0c0300)
70 void *operator new(unsigned int, int);
71 void *operator new[](unsigned int, int);
76 #define UHCI_HCRESET 2
80 #define UHCI_SWDGB 0x20
82 #define UHCI_MAXP 0x80
84 #define TD_TOKEN_DATATOGGLE (1 << 19)
86 #define TD_CONTROL_ACTIVE (1 << 23)
88 #define UHCI_INVALID 1
90 #define UHCI_QUEUEHEAD 2
91 #define UHCI_TRANSFERDESC 0
93 void uhci::init_structures() {
94 /* new does not give aligned pointers */
96 td
= new (16) uhci::transfer_descriptor
;
97 td
->link_ptr
= UHCI_INVALID
;
102 qh
= new (16) queue_head
;
103 qh
->head_ptr
= UHCI_INVALID
;
104 qh
->element_ptr
= (u32
)td
| UHCI_TRANSFERDESC
;
107 /* Create frame list pointer */
109 fp
= (frame_pointer
*)new (4096) char[4096];
110 fp
[last_fp
++] = (u32
)qh
| UHCI_VALID
| UHCI_QUEUEHEAD
;
112 for (int i
= last_fp
; i
< 1024; i
++)
113 fp
[i
] = UHCI_INVALID
;
115 /* give fp to the uhci */
117 __asm__("cli\nhlt"::"a"(fp
)); //critical("oh my cthulhu! frame list is not aligned!");
118 pciid
.outl(uhci_flbaseadd
, (u32
)fp
);
122 arch::unlock_irqs(pciid
.irq
);
123 __asm__("cli\nhlt"::"a"(0xdeadbeef));
127 void uhci::bulk_transfer(int pid
, void *val
, int length
, int address
, int endp
) {
130 td
->link_ptr
= UHCI_INVALID
;
131 td
->buffer
= (u32
)val
;
132 td
->control
= 1 << 26 | 1 << 24 | 1 << 23;
133 td
->token
= (length
- 1) << 21 | pid
| address
<< 8 | endp
<< 15;
135 pciid
.outw(uhci_command
, UHCI_RUN
);
136 /* Wait until frame is completed */
137 while (!(pciid
.inw(uhci_status
) & 1));
138 pciid
.outw(uhci_command
, UHCI_STOP
);
140 /* Clear uhci status */
141 pciid
.outw(uhci_status
, 0xffff);
144 /* control transfer */
145 void *uhci::control_transfer(int pid
, void *val
, int length
, int rlength
, u8 address
) {
146 /* Control message */
150 td
->link_ptr
= (u32
)new (16) transfer_descriptor
;
151 td
->buffer
= (u32
)val
;
152 td
->control
= 1 << 26 | 1 << 23;
153 td
->token
= (length
- 1) << 21 | pid
| address
<< 8;
157 transfer_descriptor
*status
= (transfer_descriptor
*)td
->link_ptr
;
159 /* optional data stage */
161 buffer
= (u8
*)new char[rlength
];
163 /* In message (get data from device) */
164 transfer_descriptor
*rp
= (transfer_descriptor
*)td
->link_ptr
;
165 rp
->link_ptr
= (u32
)new (16) transfer_descriptor
;
166 status
= (transfer_descriptor
*)rp
->link_ptr
;
167 rp
->buffer
= (u32
)buffer
;
168 rp
->control
= 1 << 26 | 1 << 23;
169 rp
->token
= (rlength
- 1) << 21 | usb::pid_in
| address
<< 8;
173 status
->link_ptr
= UHCI_INVALID
;
175 status
->control
= 1 << 26 | 1 << 23 | 1 << 24;
177 status
->token
= 0x7ff << 21 | usb::pid_out
| address
<< 8;
179 status
->token
= 0x7ff << 21 | usb::pid_in
| address
<< 8;
181 pciid
.outw(uhci_command
, UHCI_RUN
);
182 /* Wait until frame is completed */
183 while (!(pciid
.inw(uhci_status
) & 1));// __asm__("sti\nhlt");
184 pciid
.outw(uhci_command
, UHCI_STOP
);
186 /* Clear uhci status */
187 pciid
.outw(uhci_status
, 0xffff);
192 int uhci::get_free_address() {
197 manes::manec::get()->get
<services::interrupt_manager
>("/interrupt_manager")->register_interrupt(pciid
.irq
, delegate
<void>::method(this, &uhci::irq
));
200 pciid
.outw(uhci_command
, UHCI_STOP
| UHCI_HCRESET
);
201 while (pciid
.inw(uhci_command
) & UHCI_HCRESET
);
203 /* Prepare structures */
204 // uhci_init_structures(pciaddr);
209 pciid
.outw(uhci_portsc1
, 0x200);
210 pciid
.outw(uhci_portsc1
+ 2, 0x200);
214 pciid
.outw(uhci_portsc1
, 0);
215 pciid
.outw(uhci_portsc1
+ 2, 0);
218 void uhci::scan_bus(delegate
<void, int> device_connected
) {
219 /* Wait for connected devices */
220 u16 read1
= 0x80, read2
= 0x80;
222 if ((read1
= pciid
.inw(uhci_portsc1
)) == 0x80 && (read2
= pciid
.inw(uhci_portsc1
+ 2)) == 0x80)
227 pciid
.outw(uhci_portsc1
, 4);
228 device_connected(uhci_portsc1
);
233 pciid
.outw(uhci_portsc1
+ 2, 4);
234 device_connected(uhci_portsc1
+ 2);
237 read2
= pciid
.inw(uhci_portsc1
+2);
241 void uhci::register_type() {
242 manes::manec::get()->register_driver
<uhci
>("uhci", "pci", delegate
<bool, p
<did
> >::function(&uhci::check_device
));