Rev 1600 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1600 | Rev 1605 | ||
---|---|---|---|
1 | #define UHCI_USBLEGSUP 0x00c0 /* legacy support */ |
1 | #define UHCI_USBLEGSUP 0x00c0 /* legacy support */ |
2 | #define UHCI_USBCMD 0 /* command register */ |
2 | #define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ |
3 | #define UHCI_USBINTR 4 /* interrupt register */ |
- | |
4 | #define UHCI_USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ |
3 | #define UHCI_USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ |
5 | #define UHCI_USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ |
4 | #define UHCI_USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ |
6 | #define UHCI_USBCMD_RUN 0x0001 /* RUN/STOP bit */ |
5 | |
- | 6 | ||
- | 7 | #define UHCI_USBCMD 0 /* command register */ |
|
- | 8 | #define UHCI_USBINTR 4 /* interrupt register */ |
|
- | 9 | #define UHCI_USBCMD_RUN 0x0001 /* RUN/STOP bit */ |
|
7 | #define UHCI_USBCMD_HCRESET 0x0002 /* Host Controller reset */ |
10 | #define UHCI_USBCMD_HCRESET 0x0002 /* Host Controller reset */ |
8 | #define UHCI_USBCMD_EGSM 0x0008 /* Global Suspend Mode */ |
11 | #define UHCI_USBCMD_EGSM 0x0008 /* Global Suspend Mode */ |
9 | #define UHCI_USBCMD_CONFIGURE 0x0040 /* Config Flag */ |
12 | #define UHCI_USBCMD_CONFIGURE 0x0040 /* Config Flag */ |
10 | #define UHCI_USBINTR_RESUME 0x0002 /* Resume interrupt enable */ |
13 | #define UHCI_USBINTR_RESUME 0x0002 /* Resume interrupt enable */ |
11 | 14 | ||
12 | 15 | ||
13 | #define USBCMD 0 |
16 | #define USBCMD 0 |
14 | #define USBCMD_RS 0x0001 /* Run/Stop */ |
17 | #define USBCMD_RS 0x0001 /* Run/Stop */ |
15 | #define USBCMD_HCRESET 0x0002 /* Host reset */ |
18 | #define USBCMD_HCRESET 0x0002 /* Host reset */ |
16 | #define USBCMD_GRESET 0x0004 /* Global reset */ |
19 | #define USBCMD_GRESET 0x0004 /* Global reset */ |
17 | #define USBCMD_EGSM 0x0008 /* Global Suspend Mode */ |
20 | #define USBCMD_EGSM 0x0008 /* Global Suspend Mode */ |
18 | #define USBCMD_FGR 0x0010 /* Force Global Resume */ |
21 | #define USBCMD_FGR 0x0010 /* Force Global Resume */ |
19 | #define USBCMD_SWDBG 0x0020 /* SW Debug mode */ |
22 | #define USBCMD_SWDBG 0x0020 /* SW Debug mode */ |
20 | #define USBCMD_CF 0x0040 /* Config Flag (sw only) */ |
23 | #define USBCMD_CF 0x0040 /* Config Flag (sw only) */ |
21 | #define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */ |
24 | #define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */ |
22 | 25 | ||
23 | #define USBSTS 2 |
26 | #define USBSTS 2 |
24 | #define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */ |
27 | #define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */ |
25 | #define USBSTS_ERROR 0x0002 /* Interrupt due to error */ |
28 | #define USBSTS_ERROR 0x0002 /* Interrupt due to error */ |
26 | #define USBSTS_RD 0x0004 /* Resume Detect */ |
29 | #define USBSTS_RD 0x0004 /* Resume Detect */ |
27 | #define USBSTS_HSE 0x0008 /* Host System Error: PCI problems */ |
30 | #define USBSTS_HSE 0x0008 /* Host System Error: PCI problems */ |
28 | #define USBSTS_HCPE 0x0010 /* Host Controller Process Error: |
31 | #define USBSTS_HCPE 0x0010 /* Host Controller Process Error: |
29 | * the schedule is buggy */ |
32 | * the schedule is buggy */ |
30 | #define USBSTS_HCH 0x0020 /* HC Halted */ |
33 | #define USBSTS_HCH 0x0020 /* HC Halted */ |
31 | 34 | ||
32 | 35 | ||
33 | #define USBFRNUM 6 |
36 | #define USBFRNUM 6 |
34 | #define USBFLBASEADD 8 |
37 | #define USBFLBASEADD 8 |
35 | #define USBSOF 12 |
38 | #define USBSOF 12 |
36 | #define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */ |
39 | #define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */ |
37 | 40 | ||
38 | #define USBPORTSC1 16 |
41 | #define USBPORTSC1 16 |
39 | #define USBPORTSC2 18 |
42 | #define USBPORTSC2 18 |
40 | 43 | ||
41 | #define UHCI_RH_MAXCHILD 7 |
44 | #define UHCI_RH_MAXCHILD 7 |
42 | 45 | ||
43 | 46 | ||
44 | /* |
47 | /* |
45 | * Make sure the controller is completely inactive, unable to |
48 | * Make sure the controller is completely inactive, unable to |
46 | * generate interrupts or do DMA. |
49 | * generate interrupts or do DMA. |
47 | */ |
50 | */ |
48 | void uhci_reset_hc(hc_t *hc) |
51 | void uhci_reset_hc(hc_t *hc) |
49 | { |
52 | { |
50 | /* Turn off PIRQ enable and SMI enable. (This also turns off the |
53 | /* Turn off PIRQ enable and SMI enable. (This also turns off the |
51 | * BIOS's USB Legacy Support.) Turn off all the R/WC bits too. |
54 | * BIOS's USB Legacy Support.) Turn off all the R/WC bits too. |
52 | */ |
55 | */ |
53 | pciWriteWord(hc->PciTag, UHCI_USBLEGSUP, UHCI_USBLEGSUP_RWC); |
56 | pciWriteWord(hc->PciTag, UHCI_USBLEGSUP, UHCI_USBLEGSUP_RWC); |
54 | 57 | ||
55 | /* Reset the HC - this will force us to get a |
58 | /* Reset the HC - this will force us to get a |
56 | * new notification of any already connected |
59 | * new notification of any already connected |
57 | * ports due to the virtual disconnect that it |
60 | * ports due to the virtual disconnect that it |
58 | * implies. |
61 | * implies. |
59 | */ |
62 | */ |
60 | out16(hc->iobase + UHCI_USBCMD, UHCI_USBCMD_HCRESET); |
63 | out16(hc->iobase + UHCI_USBCMD, UHCI_USBCMD_HCRESET); |
61 | __asm__ __volatile__ ("":::"memory"); |
64 | __asm__ __volatile__ ("":::"memory"); |
62 | 65 | ||
63 | delay(20/10); |
66 | delay(20/10); |
64 | 67 | ||
65 | if (in16(hc->iobase + UHCI_USBCMD) & UHCI_USBCMD_HCRESET) |
68 | if (in16(hc->iobase + UHCI_USBCMD) & UHCI_USBCMD_HCRESET) |
66 | dbgprintf("HCRESET not completed yet!\n"); |
69 | dbgprintf("HCRESET not completed yet!\n"); |
67 | 70 | ||
68 | /* Just to be safe, disable interrupt requests and |
71 | /* Just to be safe, disable interrupt requests and |
69 | * make sure the controller is stopped. |
72 | * make sure the controller is stopped. |
70 | */ |
73 | */ |
71 | out16(hc->iobase + UHCI_USBINTR, 0); |
74 | out16(hc->iobase + UHCI_USBINTR, 0); |
72 | out16(hc->iobase + UHCI_USBCMD, 0); |
75 | out16(hc->iobase + UHCI_USBCMD, 0); |
73 | }; |
76 | }; |
74 | 77 | ||
75 | int uhci_check_and_reset_hc(hc_t *hc) |
78 | int uhci_check_and_reset_hc(hc_t *hc) |
76 | { |
79 | { |
77 | u16_t legsup; |
80 | u16_t legsup; |
78 | unsigned int cmd, intr; |
81 | unsigned int cmd, intr; |
79 | 82 | ||
80 | /* |
83 | /* |
81 | * When restarting a suspended controller, we expect all the |
84 | * When restarting a suspended controller, we expect all the |
82 | * settings to be the same as we left them: |
85 | * settings to be the same as we left them: |
83 | * |
86 | * |
84 | * PIRQ and SMI disabled, no R/W bits set in USBLEGSUP; |
87 | * PIRQ and SMI disabled, no R/W bits set in USBLEGSUP; |
85 | * Controller is stopped and configured with EGSM set; |
88 | * Controller is stopped and configured with EGSM set; |
86 | * No interrupts enabled except possibly Resume Detect. |
89 | * No interrupts enabled except possibly Resume Detect. |
87 | * |
90 | * |
88 | * If any of these conditions are violated we do a complete reset. |
91 | * If any of these conditions are violated we do a complete reset. |
89 | */ |
92 | */ |
90 | legsup = pciReadWord(hc->PciTag, UHCI_USBLEGSUP); |
93 | legsup = pciReadWord(hc->PciTag, UHCI_USBLEGSUP); |
91 | if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) { |
94 | if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) { |
92 | dbgprintf("%s: legsup = 0x%04x\n",__FUNCTION__, legsup); |
95 | dbgprintf("%s: legsup = 0x%04x\n",__FUNCTION__, legsup); |
93 | goto reset_needed; |
96 | goto reset_needed; |
94 | } |
97 | } |
95 | 98 | ||
96 | cmd = in16(hc->iobase + UHCI_USBCMD); |
99 | cmd = in16(hc->iobase + UHCI_USBCMD); |
97 | if ( (cmd & UHCI_USBCMD_RUN) || |
100 | if ( (cmd & UHCI_USBCMD_RUN) || |
98 | !(cmd & UHCI_USBCMD_CONFIGURE) || |
101 | !(cmd & UHCI_USBCMD_CONFIGURE) || |
99 | !(cmd & UHCI_USBCMD_EGSM)) |
102 | !(cmd & UHCI_USBCMD_EGSM)) |
100 | { |
103 | { |
101 | dbgprintf("%s: cmd = 0x%04x\n", __FUNCTION__, cmd); |
104 | dbgprintf("%s: cmd = 0x%04x\n", __FUNCTION__, cmd); |
102 | goto reset_needed; |
105 | goto reset_needed; |
103 | } |
106 | } |
104 | 107 | ||
105 | intr = in16(hc->iobase + UHCI_USBINTR); |
108 | intr = in16(hc->iobase + UHCI_USBINTR); |
106 | if (intr & (~UHCI_USBINTR_RESUME)) |
109 | if (intr & (~UHCI_USBINTR_RESUME)) |
107 | { |
110 | { |
108 | dbgprintf("%s: intr = 0x%04x\n", __FUNCTION__, intr); |
111 | dbgprintf("%s: intr = 0x%04x\n", __FUNCTION__, intr); |
109 | goto reset_needed; |
112 | goto reset_needed; |
110 | } |
113 | } |
111 | return 0; |
114 | return 0; |
112 | 115 | ||
113 | reset_needed: |
116 | reset_needed: |
114 | dbgprintf("Performing full reset\n"); |
117 | dbgprintf("Performing full reset\n"); |
115 | uhci_reset_hc(hc); |
118 | uhci_reset_hc(hc); |
116 | return 1; |
119 | return 1; |
117 | } |
120 | } |
118 | 121 | ||
- | 122 | void hc_interrupt() |
|
- | 123 | { |
|
- | 124 | hc_t *hc; |
|
- | 125 | ||
- | 126 | printf("USB interrupt\n"); |
|
- | 127 | ||
- | 128 | hc = (hc_t*)hc_list.next; |
|
- | 129 | ||
- | 130 | while( &hc->list != &hc_list) |
|
- | 131 | { |
|
- | 132 | hc_t *tmp; |
|
- | 133 | u16_t status; |
|
- | 134 | ||
- | 135 | tmp = hc; |
|
- | 136 | hc = (hc_t*)hc->list.next; |
|
- | 137 | ||
- | 138 | status = in16(tmp->iobase + USBSTS); |
|
- | 139 | if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */ |
|
- | 140 | continue; |
|
- | 141 | out16(tmp->iobase + USBSTS, status); /* Clear it */ |
|
- | 142 | } |
|
- | 143 | ||
- | 144 | }; |
|
- | 145 | ||
- | 146 | ||
119 | 147 | ||
120 | bool init_hc(hc_t *hc) |
148 | bool init_hc(hc_t *hc) |
121 | { |
149 | { |
122 | int port; |
150 | int port; |
123 | u32_t ifl; |
151 | u32_t ifl; |
124 | u16_t dev_status; |
152 | u16_t dev_status; |
125 | int i; |
153 | td_t *td; |
- | 154 | int i; |
|
126 | 155 | ||
127 | dbgprintf("\n\ninit uhci %x\n\n", hc->pciId); |
156 | dbgprintf("\n\ninit uhci %x\n\n", hc->pciId); |
128 | 157 | ||
129 | for(i=0;i<6;i++) |
158 | for(i=0;i<6;i++) |
130 | { |
159 | { |
131 | if(hc->ioBase[i]){ |
160 | if(hc->ioBase[i]){ |
132 | hc->iobase = hc->ioBase[i]; |
161 | hc->iobase = hc->ioBase[i]; |
133 | // dbgprintf("Io base_%d 0x%x\n", i,hc->ioBase[i]); |
162 | // dbgprintf("Io base_%d 0x%x\n", i,hc->ioBase[i]); |
134 | break; |
163 | break; |
135 | }; |
164 | }; |
136 | }; |
165 | }; |
137 | 166 | ||
138 | /* The UHCI spec says devices must have 2 ports, and goes on to say |
167 | /* The UHCI spec says devices must have 2 ports, and goes on to say |
139 | * they may have more but gives no way to determine how many there |
168 | * they may have more but gives no way to determine how many there |
140 | * are. However according to the UHCI spec, Bit 7 of the port |
169 | * are. However according to the UHCI spec, Bit 7 of the port |
141 | * status and control register is always set to 1. So we try to |
170 | * status and control register is always set to 1. So we try to |
142 | * use this to our advantage. Another common failure mode when |
171 | * use this to our advantage. Another common failure mode when |
143 | * a nonexistent register is addressed is to return all ones, so |
172 | * a nonexistent register is addressed is to return all ones, so |
144 | * we test for that also. |
173 | * we test for that also. |
145 | */ |
174 | */ |
146 | for (port = 0; port < 2; port++) |
175 | for (port = 0; port < 2; port++) |
147 | { |
176 | { |
148 | u32_t status; |
177 | u32_t status; |
149 | 178 | ||
150 | status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
179 | status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
151 | dbgprintf("port%d status %x\n", port, status); |
180 | dbgprintf("port%d status %x\n", port, status); |
152 | if (!(status & 0x0080) || status == 0xffff) |
181 | if (!(status & 0x0080) || status == 0xffff) |
153 | break; |
182 | break; |
154 | } |
183 | } |
155 | dbgprintf("detected %d ports\n\n", port); |
184 | dbgprintf("detected %d ports\n\n", port); |
156 | 185 | ||
157 | hc->numports = port; |
186 | hc->numports = port; |
158 | 187 | ||
159 | /* Kick BIOS off this hardware and reset if the controller |
188 | /* Kick BIOS off this hardware and reset if the controller |
160 | * isn't already safely quiescent. |
189 | * isn't already safely quiescent. |
161 | */ |
190 | */ |
162 | uhci_check_and_reset_hc(hc); |
191 | uhci_check_and_reset_hc(hc); |
163 | 192 | ||
164 | hc->frame_base = (u32_t*)KernelAlloc(4096); |
193 | hc->frame_base = (u32_t*)KernelAlloc(4096); |
165 | hc->frame_dma = GetPgAddr(hc->frame_base); |
194 | hc->frame_dma = GetPgAddr(hc->frame_base); |
166 | hc->frame_number = 0; |
195 | hc->frame_number = 0; |
167 | 196 | ||
- | 197 | ||
- | 198 | for (i = 0; i < UHCI_NUM_SKELQH; i++) |
|
- | 199 | { |
|
168 | qh_t *qh = alloc_qh(); |
200 | qh_t *qh = alloc_qh(); |
169 | 201 | ||
170 | qh->qlink = 1; |
202 | qh->qlink = 1; |
171 | qh->qelem = 1; |
203 | qh->qelem = 1; |
172 | 204 | ||
173 | hc->qh1 = qh; |
205 | hc->qh[i] = qh; |
- | 206 | } |
|
- | 207 | for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i) |
|
- | 208 | hc->qh[i]->qlink = hc->qh[SKEL_ASYNC]->dma | 2; |
|
- | 209 | ||
- | 210 | /* |
|
- | 211 | td = alloc_td(); |
|
- | 212 | ||
- | 213 | td->link = 1; |
|
174 | 214 | td->status = (1<<24) | (1<<23) ; |
|
- | 215 | td->token = TOKEN( 0x7FF, DATA0, 0, 0, 0xE1); |
|
- | 216 | td->buffer = 0; |
|
- | 217 | td->bk = NULL; |
|
175 | // dbgprintf("alloc qh %x dma %x\n", qh, qh->dma); |
218 | */ |
- | 219 | ||
176 | 220 | for (i = 0; i < 1024; i++) |
|
- | 221 | { |
|
- | 222 | int qnum; |
|
- | 223 | ||
- | 224 | qnum = 8 - (int) __bsf( i | 1024); |
|
- | 225 | ||
- | 226 | if (qnum <= 1) |
|
- | 227 | qnum = 9; |
|
- | 228 | ||
- | 229 | hc->frame_base[i] = hc->qh[qnum]->dma | 2; |
|
177 | for(i=0; i<1024; i++) |
230 | } |
178 | hc->frame_base[i] = qh->dma | 2; |
231 | |
179 | 232 | mb(); |
|
180 | 233 | ||
181 | /* Set the frame length to the default: 1 ms exactly */ |
234 | /* Set the frame length to the default: 1 ms exactly */ |
182 | out8(hc->iobase + USBSOF, USBSOF_DEFAULT); |
235 | out8(hc->iobase + USBSOF, USBSOF_DEFAULT); |
183 | 236 | ||
184 | /* Store the frame list base address */ |
237 | /* Store the frame list base address */ |
185 | out32(hc->iobase + USBFLBASEADD, hc->frame_dma); |
238 | out32(hc->iobase + USBFLBASEADD, hc->frame_dma); |
186 | 239 | ||
187 | /* Set the current frame number */ |
240 | /* Set the current frame number */ |
188 | out16(hc->iobase + USBFRNUM, 0); |
241 | out16(hc->iobase + USBFRNUM, 0); |
189 | 242 | ||
190 | out16(hc->iobase + USBSTS, 0x3F); |
243 | out16(hc->iobase + USBSTS, 0x3F); |
191 | out16(hc->iobase + USBCMD, USBCMD_RS | USBCMD_CF | |
244 | |
- | 245 | out16(hc->iobase + UHCI_USBINTR, 4); |
|
- | 246 | ||
- | 247 | AttachIntHandler(hc->irq_line, hc_interrupt, 0); |
|
- | 248 | ||
- | 249 | pciWriteWord(hc->PciTag, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT); |
|
- | 250 | ||
- | 251 | out16(hc->iobase + USBCMD, USBCMD_RS | USBCMD_CF | |
|
192 | USBCMD_MAXP); |
252 | USBCMD_MAXP); |
193 | 253 | ||
194 | for (port = 0; port < hc->numports; ++port) |
254 | for (port = 0; port < hc->numports; ++port) |
195 | out16(hc->iobase + USBPORTSC1 + (port * 2), 0x200); |
255 | out16(hc->iobase + USBPORTSC1 + (port * 2), 0x200); |
196 | delay(100/10); |
256 | delay(100/10); |
197 | 257 | ||
198 | for (port = 0; port < 2; ++port) |
258 | for (port = 0; port < 2; ++port) |
199 | { |
259 | { |
200 | time_t timeout; |
260 | time_t timeout; |
201 | 261 | ||
202 | u32_t status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
262 | u32_t status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
203 | dbgprintf("port%d status %x\n", port, status); |
263 | dbgprintf("port%d status %x\n", port, status); |
204 | 264 | ||
205 | out16(hc->iobase + USBPORTSC1 + (port * 2), 0); |
265 | out16(hc->iobase + USBPORTSC1 + (port * 2), 0); |
206 | 266 | ||
207 | timeout = 100/10; |
267 | timeout = 100/10; |
208 | while(timeout--) |
268 | while(timeout--) |
209 | { |
269 | { |
210 | delay(10/10); |
270 | delay(10/10); |
211 | status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
271 | status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
212 | if(status & 1) |
272 | if(status & 1) |
213 | { |
273 | { |
214 | udev_t *dev = kmalloc(sizeof(udev_t),0); |
274 | udev_t *dev = kmalloc(sizeof(udev_t),0); |
215 | 275 | ||
216 | out16(hc->iobase + USBPORTSC1 + (port * 2), 0x0E); |
276 | out16(hc->iobase + USBPORTSC1 + (port * 2), 0x0E); |
217 | 277 | ||
218 | delay(20/10); |
278 | delay(20/10); |
219 | 279 | ||
220 | dbgprintf("enable port\n"); |
280 | dbgprintf("enable port\n"); |
221 | status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
281 | status = in16(hc->iobase + USBPORTSC1 + (port * 2)); |
222 | dbgprintf("port%d status %x\n", port, status); |
282 | dbgprintf("port%d status %x\n", port, status); |
223 | 283 | ||
224 | INIT_LIST_HEAD(&dev->list); |
284 | INIT_LIST_HEAD(&dev->list); |
225 | 285 | ||
226 | dev->host = hc; |
286 | dev->host = hc; |
227 | dev->port = port; |
287 | dev->port = port; |
228 | dev->ep0_size = 8; |
288 | dev->ep0_size = 8; |
229 | dev->status = status; |
289 | dev->status = status; |
230 | 290 | ||
231 | dbgprintf("port%d connected", port); |
291 | dbgprintf("port%d connected", port); |
232 | if(status & 4) |
292 | if(status & 4) |
233 | dbgprintf(" enabled"); |
293 | dbgprintf(" enabled"); |
234 | else |
294 | else |
235 | dbgprintf(" disabled"); |
295 | dbgprintf(" disabled"); |
236 | if(status & 0x100){ |
296 | if(status & 0x100){ |
237 | dev->speed = 0x4000000; |
297 | dev->speed = 0x4000000; |
238 | dbgprintf(" low speed\n"); |
298 | dbgprintf(" low speed\n"); |
239 | } else { |
299 | } else { |
240 | dev->speed = 0; |
300 | dev->speed = 0; |
241 | dbgprintf(" full speed\n"); |
301 | dbgprintf(" full speed\n"); |
242 | }; |
302 | }; |
243 | 303 | ||
244 | if(set_address(dev)) { |
304 | if(set_address(dev)) { |
245 | list_add_tail(&dev->list, &newdev_list); |
305 | list_add_tail(&dev->list, &newdev_list); |
246 | hc->port_map |= 1< |
306 | hc->port_map |= 1< |
247 | } |
307 | } |
248 | else { |
308 | else { |
249 | free(dev); |
309 | free(dev); |
250 | out16(hc->iobase + USBPORTSC1 + (port * 2), 0); |
310 | out16(hc->iobase + USBPORTSC1 + (port * 2), 0); |
251 | } |
311 | } |
252 | break; |
312 | break; |
253 | }; |
313 | }; |
254 | }; |
314 | }; |
255 | }; |
315 | }; |
256 | return true; |
316 | return true; |
257 | }; |
317 | }; |
258 | 318 | ||
259 | u16_t __attribute__((aligned(16))) |
319 | u16_t __attribute__((aligned(16))) |
260 | req_descr[4] = {0x0680,0x0100,0x0000,8}; |
320 | req_descr[4] = {0x0680,0x0100,0x0000,8}; |
261 | 321 | ||
262 | /* |
322 | /* |
263 | IN(69) OUT(E1) SETUP(2D) |
323 | IN(69) OUT(E1) SETUP(2D) |
264 | SETUP(0) IN(1) |
324 | SETUP(0) IN(1) |
265 | SETUP(0) OUT(1) OUT(0) OUT(1)...IN(1) |
325 | SETUP(0) OUT(1) OUT(0) OUT(1)...IN(1) |
266 | SETUP(0) IN(1) IN(0) IN(1)...OUT(0) |
326 | SETUP(0) IN(1) IN(0) IN(1)...OUT(0) |
267 | */ |
327 | */ |
268 | 328 | ||
269 | 329 | ||
270 | bool set_address(udev_t *dev) |
330 | bool set_address(udev_t *dev) |
271 | { |
331 | { |
272 | static udev_id = 0; |
332 | static udev_id = 0; |
273 | static udev_addr = 0; |
333 | static udev_addr = 0; |
274 | static u16_t __attribute__((aligned(16))) |
334 | static u16_t __attribute__((aligned(16))) |
275 | req_addr[4] = {0x0500,0x0001,0x0000,0x0000}; |
335 | req_addr[4] = {0x0500,0x0001,0x0000,0x0000}; |
276 | 336 | ||
277 | static u16_t __attribute__((aligned(16))) |
337 | static u16_t __attribute__((aligned(16))) |
278 | req_descr[4] = {0x0680,0x0100,0x0000,8}; |
338 | req_descr[4] = {0x0680,0x0100,0x0000,8}; |
279 | 339 | ||
280 | static u32_t data[2] __attribute__((aligned(16))); |
340 | static u32_t data[2] __attribute__((aligned(16))); |
281 | 341 | ||
282 | qh_t *qh; |
342 | qh_t *qh; |
283 | td_t *td0, *td1, *td2; |
343 | td_t *td0, *td1, *td2; |
284 | u32_t dev_status; |
344 | u32_t dev_status; |
285 | count_t timeout; |
345 | count_t timeout; |
286 | int address; |
346 | int address; |
287 | 347 | ||
288 | address = ++udev_addr; |
348 | address = ++udev_addr; |
289 | 349 | ||
290 | req_addr[1] = address; |
350 | req_addr[1] = address; |
291 | 351 | ||
292 | if( !ctrl_request(dev, &req_addr, DOUT, NULL, 0)) |
352 | if( !ctrl_request(dev, &req_addr, DOUT, NULL, 0)) |
293 | return false; |
353 | return false; |
294 | 354 | ||
295 | dev->addr = address; |
355 | dev->addr = address; |
296 | dev->id = (++udev_id << 8) | address; |
356 | dev->id = (++udev_id << 8) | address; |
297 | 357 | ||
298 | dbgprintf("set address %d\n", address); |
358 | dbgprintf("set address %d\n", address); |
299 | 359 | ||
300 | data[0] = 0; |
360 | data[0] = 0; |
301 | data[1] = 0; |
361 | data[1] = 0; |
302 | 362 | ||
303 | if( !ctrl_request(dev, &req_descr, DIN, data, 8)) |
363 | if( !ctrl_request(dev, &req_descr, DIN, data, 8)) |
304 | return false; |
364 | return false; |
305 | 365 | ||
306 | dev_descr_t *descr = (dev_descr_t*)&data; |
366 | dev_descr_t *descr = (dev_descr_t*)&data; |
307 | dev->ep0_size = descr->bMaxPacketSize0; |
367 | dev->ep0_size = descr->bMaxPacketSize0; |
308 | 368 | ||
309 | return true; |
369 | return true; |
310 | } |
370 | } |
311 | 371 | ||
312 | request_t *create_request(udev_t *dev, endp_t *enp, u32_t dir, |
372 | request_t *create_request(udev_t *dev, endp_t *enp, u32_t dir, |
313 | void *data, size_t req_size) |
373 | void *data, size_t req_size) |
314 | { |
374 | { |
315 | td_t *td, *td_prev; |
375 | td_t *td, *td_prev; |
316 | addr_t data_dma; |
376 | addr_t data_dma; |
317 | 377 | ||
318 | size_t packet_size = enp->size; |
378 | size_t packet_size = enp->size; |
319 | size_t size = req_size; |
379 | size_t size = req_size; |
320 | 380 | ||
321 | request_t *rq = (request_t*)kmalloc(sizeof(request_t),0); |
381 | request_t *rq = (request_t*)kmalloc(sizeof(request_t),0); |
322 | 382 | ||
323 | INIT_LIST_HEAD(&rq->list); |
383 | INIT_LIST_HEAD(&rq->list); |
324 | 384 | ||
325 | rq->data = (addr_t)data; |
385 | rq->data = (addr_t)data; |
326 | rq->size = req_size; |
386 | rq->size = req_size; |
327 | rq->dev = dev; |
387 | rq->dev = dev; |
328 | 388 | ||
329 | if(data) |
389 | if(data) |
330 | data_dma = DMA(data); |
390 | data_dma = DMA(data); |
331 | 391 | ||
332 | td_prev = NULL; |
392 | td_prev = NULL; |
333 | 393 | ||
334 | while(size > 0) |
394 | while(size > 0) |
335 | { |
395 | { |
336 | if ( size < packet_size) |
396 | if ( size < packet_size) |
337 | { |
397 | { |
338 | packet_size = size; |
398 | packet_size = size; |
339 | }; |
399 | }; |
340 | 400 | ||
341 | td = alloc_td(); |
401 | td = alloc_td(); |
342 | td->link = 1; |
402 | td->link = 1; |
343 | 403 | ||
344 | if(rq->td_head == NULL) |
404 | if(rq->td_head == NULL) |
345 | rq->td_head = td; |
405 | rq->td_head = td; |
346 | 406 | ||
347 | if( td_prev ) |
407 | if( td_prev ) |
348 | td_prev->link = td->dma | 4; |
408 | td_prev->link = td->dma | 4; |
349 | td->status = 0x00800000 | dev->speed; |
409 | td->status = TD_CTRL_ACTIVE | dev->speed; |
350 | td->token = TOKEN(packet_size,enp->toggle,enp->address, |
410 | td->token = TOKEN(packet_size,enp->toggle,enp->address, |
351 | dev->addr,dir); |
411 | dev->addr,dir); |
352 | td->buffer = data_dma; |
412 | td->buffer = data_dma; |
353 | td->bk = td_prev; |
413 | td->bk = td_prev; |
354 | 414 | ||
355 | td_prev = td; |
415 | td_prev = td; |
356 | 416 | ||
357 | data_dma+= packet_size; |
417 | data_dma+= packet_size; |
358 | size-= packet_size; |
418 | size-= packet_size; |
359 | enp->toggle ^= DATA1; |
419 | enp->toggle ^= DATA1; |
360 | } |
420 | }; |
361 | rq->td_tail = td; |
421 | |
- | 422 | td->status |= TD_CTRL_IOC; |
|
- | 423 | rq->td_tail = td; |
|
362 | /* |
424 | return rq; |
363 | dbgprintf("create request %x\n" |
- | |
364 | "head %x\n" |
- | |
365 | "tail %x\n" |
- | |
366 | "data %x\n" |
- | |
367 | "size %x\n", |
- | |
368 | rq, rq->td_head, rq->td_tail, |
- | |
369 | rq->data, rq->size); |
- | |
370 | */ |
- | |
371 | return rq; |
- | |
372 | } |
425 | } |
373 | 426 | ||
374 | bool ctrl_request(udev_t *dev, void *req, u32_t pid, |
427 | bool ctrl_request(udev_t *dev, void *req, u32_t pid, |
375 | void *data, size_t req_size) |
428 | void *data, size_t req_size) |
376 | { |
429 | { |
377 | size_t packet_size = dev->ep0_size; |
430 | size_t packet_size = dev->ep0_size; |
378 | size_t size = req_size; |
431 | size_t size = req_size; |
379 | u32_t toggle = DATA1; |
432 | u32_t toggle = DATA1; |
380 | 433 | ||
381 | td_t *td0, *td, *td_prev; |
434 | td_t *td0, *td, *td_prev; |
382 | qh_t *qh; |
435 | qh_t *qh; |
383 | addr_t data_dma = 0; |
436 | addr_t data_dma = 0; |
384 | bool retval; |
437 | bool retval; |
385 | 438 | ||
386 | td0 = alloc_td(); |
439 | td0 = alloc_td(); |
387 | 440 | ||
388 | td0->status = 0x00800000 | dev->speed; |
441 | td0->status = 0x00800000 | dev->speed; |
389 | td0->token = TOKEN( 8, DATA0, 0, dev->addr, 0x2D); |
442 | td0->token = TOKEN( 8, DATA0, 0, dev->addr, 0x2D); |
390 | td0->buffer = DMA(req); |
443 | td0->buffer = DMA(req); |
391 | td0->bk = NULL; |
444 | td0->bk = NULL; |
392 | 445 | ||
393 | if(data) |
446 | if(data) |
394 | data_dma = DMA(data); |
447 | data_dma = DMA(data); |
395 | 448 | ||
396 | td_prev = td0; |
449 | td_prev = td0; |
397 | 450 | ||
398 | while(size > 0) |
451 | while(size > 0) |
399 | { |
452 | { |
400 | if ( size < packet_size) |
453 | if ( size < packet_size) |
401 | { |
454 | { |
402 | packet_size = size; |
455 | packet_size = size; |
403 | }; |
456 | }; |
404 | 457 | ||
405 | td = alloc_td(); |
458 | td = alloc_td(); |
406 | td_prev->link = td->dma | 4; |
459 | td_prev->link = td->dma | 4; |
407 | td->status = 0x00800000 | dev->speed; |
460 | td->status = TD_CTRL_ACTIVE | dev->speed; |
408 | td->token = TOKEN(packet_size, toggle, 0,dev->addr, pid); |
461 | td->token = TOKEN(packet_size, toggle, 0,dev->addr, pid); |
409 | td->buffer = data_dma; |
462 | td->buffer = data_dma; |
410 | td->bk = td_prev; |
463 | td->bk = td_prev; |
411 | 464 | ||
412 | td_prev = td; |
465 | td_prev = td; |
413 | 466 | ||
414 | data_dma+= packet_size; |
467 | data_dma+= packet_size; |
415 | size-= packet_size; |
468 | size-= packet_size; |
416 | toggle ^= DATA1; |
469 | toggle ^= DATA1; |
417 | } |
470 | } |
418 | 471 | ||
419 | td = alloc_td(); |
472 | td = alloc_td(); |
420 | td_prev->link = td->dma | 4; |
473 | td_prev->link = td->dma | 4; |
421 | 474 | ||
422 | pid = (pid == DIN) ? DOUT : DIN; |
475 | pid = (pid == DIN) ? DOUT : DIN; |
423 | 476 | ||
424 | td->link = 1; |
477 | td->link = 1; |
425 | td->status = 0x00800000 | dev->speed; |
478 | td->status = TD_CTRL_ACTIVE | TD_CTRL_IOC | dev->speed ; |
426 | td->token = (0x7FF<<21)|DATA1|(dev->addr<<8)|pid; |
479 | td->token = (0x7FF<<21)|DATA1|(dev->addr<<8)|pid; |
427 | td->buffer = 0; |
480 | td->buffer = 0; |
428 | td->bk = td_prev; |
481 | td->bk = td_prev; |
429 | 482 | ||
430 | qh = dev->host->qh1; |
483 | qh = dev->host->qh[SKEL_ASYNC]; |
431 | 484 | ||
- | 485 | qh->qelem = td0->dma; |
|
- | 486 | ||
432 | qh->qelem = td0->dma; |
487 | mb(); |
433 | __asm__ __volatile__ ("":::"memory"); |
488 | // __asm__ __volatile__ ("":::"memory"); |
434 | 489 | ||
435 | count_t timeout = 25; |
490 | count_t timeout = 25; |
436 | while(timeout--){ |
491 | while(timeout--){ |
437 | delay(10/10); |
492 | delay(10/10); |
438 | if( !(td->status & TD_CTRL_ACTIVE)) |
493 | if( !(td->status & TD_CTRL_ACTIVE)) |
439 | break; |
494 | break; |
440 | } |
495 | } |
441 | 496 | ||
442 | if( (td0->status & TD_ANY_ERROR) || |
497 | if( (td0->status & TD_ANY_ERROR) || |
443 | (td_prev->status & TD_ANY_ERROR) || |
498 | (td_prev->status & TD_ANY_ERROR) || |
444 | (td->status & TD_ANY_ERROR)) |
499 | (td->status & TD_ANY_ERROR)) |
445 | { |
500 | { |
446 | u32_t dev_status = in16(dev->host->iobase + USBSTS); |
501 | u32_t dev_status = in16(dev->host->iobase + USBSTS); |
447 | 502 | ||
448 | dbgprintf("\nframe %x, cmd %x status %x\n", |
503 | dbgprintf("\nframe %x, cmd %x status %x\n", |
449 | in16(dev->host->iobase + USBFRNUM), |
504 | in16(dev->host->iobase + USBFRNUM), |
450 | in16(dev->host->iobase + USBCMD), |
505 | in16(dev->host->iobase + USBCMD), |
451 | dev_status); |
506 | dev_status); |
452 | dbgprintf("td0 status %x\n",td0->status); |
507 | dbgprintf("td0 status %x\n",td0->status); |
453 | dbgprintf("td_prev status %x\n",td_prev->status); |
508 | dbgprintf("td_prev status %x\n",td_prev->status); |
454 | dbgprintf("td status %x\n",td->status); |
509 | dbgprintf("td status %x\n",td->status); |
455 | dbgprintf("qh %x \n", qh->qelem); |
510 | dbgprintf("qh %x \n", qh->qelem); |
456 | 511 | ||
457 | retval = false; |
512 | retval = false; |
458 | } else retval = true; |
513 | } else retval = true; |
459 | 514 | ||
460 | do |
515 | do |
461 | { |
516 | { |
462 | td_prev = td->bk; |
517 | td_prev = td->bk; |
463 | free_td(td); |
518 | free_td(td); |
464 | td = td_prev; |
519 | td = td_prev; |
465 | }while( td != NULL); |
520 | }while( td != NULL); |
466 | 521 | ||
467 | return retval; |
522 | return retval; |
468 | }; |
523 | }; |
469 | 524 | ||
470 | 525 | ||
471 | bool init_device(udev_t *dev) |
526 | bool init_device(udev_t *dev) |
472 | { |
527 | { |
473 | static u16_t __attribute__((aligned(16))) |
528 | static u16_t __attribute__((aligned(16))) |
474 | req_descr[4] = {0x0680,0x0100,0x0000,18}; |
529 | req_descr[4] = {0x0680,0x0100,0x0000,18}; |
475 | 530 | ||
476 | static u16_t __attribute__((aligned(16))) |
531 | static u16_t __attribute__((aligned(16))) |
477 | req_conf[4] = {0x0680,0x0200,0x0000,9}; |
532 | req_conf[4] = {0x0680,0x0200,0x0000,9}; |
478 | 533 | ||
479 | static dev_descr_t __attribute__((aligned(16))) descr; |
534 | static dev_descr_t __attribute__((aligned(16))) descr; |
480 | 535 | ||
481 | interface_descr_t *interface; |
536 | interface_descr_t *interface; |
482 | 537 | ||
483 | u32_t data[8]; |
538 | u32_t data[8]; |
484 | 539 | ||
485 | u8_t *dptr; |
540 | u8_t *dptr; |
486 | conf_descr_t *conf; |
541 | conf_descr_t *conf; |
487 | 542 | ||
488 | dbgprintf("\ninit device %x, host %x, port %d\n\n", |
543 | dbgprintf("\ninit device %x, host %x, port %d\n\n", |
489 | dev->id, dev->host->pciId, dev->port); |
544 | dev->id, dev->host->pciId, dev->port); |
490 | 545 | ||
491 | if( !ctrl_request(dev, req_descr, DIN, &descr, 18)) |
546 | if( !ctrl_request(dev, req_descr, DIN, &descr, 18)) |
492 | return; |
547 | return; |
493 | 548 | ||
494 | dev->dev_descr = descr; |
549 | dev->dev_descr = descr; |
495 | 550 | ||
496 | dbgprintf("device descriptor:\n\n" |
551 | dbgprintf("device descriptor:\n\n" |
497 | "bLength %d\n" |
552 | "bLength %d\n" |
498 | "bDescriptorType %d\n" |
553 | "bDescriptorType %d\n" |
499 | "bcdUSB %x\n" |
554 | "bcdUSB %x\n" |
500 | "bDeviceClass %x\n" |
555 | "bDeviceClass %x\n" |
501 | "bDeviceSubClass %x\n" |
556 | "bDeviceSubClass %x\n" |
502 | "bDeviceProtocol %x\n" |
557 | "bDeviceProtocol %x\n" |
503 | "bMaxPacketSize0 %d\n" |
558 | "bMaxPacketSize0 %d\n" |
504 | "idVendor %x\n" |
559 | "idVendor %x\n" |
505 | "idProduct %x\n" |
560 | "idProduct %x\n" |
506 | "bcdDevice %x\n" |
561 | "bcdDevice %x\n" |
507 | "iManufacturer %x\n" |
562 | "iManufacturer %x\n" |
508 | "iProduct %x\n" |
563 | "iProduct %x\n" |
509 | "iSerialNumber %x\n" |
564 | "iSerialNumber %x\n" |
510 | "bNumConfigurations %d\n\n", |
565 | "bNumConfigurations %d\n\n", |
511 | descr.bLength, descr.bDescriptorType, |
566 | descr.bLength, descr.bDescriptorType, |
512 | descr.bcdUSB, descr.bDeviceClass, |
567 | descr.bcdUSB, descr.bDeviceClass, |
513 | descr.bDeviceSubClass, descr.bDeviceProtocol, |
568 | descr.bDeviceSubClass, descr.bDeviceProtocol, |
514 | descr.bMaxPacketSize0, descr.idVendor, |
569 | descr.bMaxPacketSize0, descr.idVendor, |
515 | descr.idProduct, descr.bcdDevice, |
570 | descr.idProduct, descr.bcdDevice, |
516 | descr.iManufacturer, descr.iProduct, |
571 | descr.iManufacturer, descr.iProduct, |
517 | descr.iSerialNumber, descr.bNumConfigurations); |
572 | descr.iSerialNumber, descr.bNumConfigurations); |
518 | 573 | ||
519 | req_conf[3] = 8; |
574 | req_conf[3] = 8; |
520 | if( !ctrl_request(dev, req_conf, DIN, &data, 8)) |
575 | if( !ctrl_request(dev, req_conf, DIN, &data, 8)) |
521 | return; |
576 | return; |
522 | 577 | ||
523 | conf = (conf_descr_t*)&data; |
578 | conf = (conf_descr_t*)&data; |
524 | 579 | ||
525 | size_t conf_size = conf->wTotalLength; |
580 | size_t conf_size = conf->wTotalLength; |
526 | 581 | ||
527 | req_conf[3] = conf_size; |
582 | req_conf[3] = conf_size; |
528 | conf = malloc(conf_size); |
583 | conf = malloc(conf_size); |
529 | 584 | ||
530 | if( !ctrl_request(dev, req_conf, DIN, conf, conf_size)) |
585 | if( !ctrl_request(dev, req_conf, DIN, conf, conf_size)) |
531 | return; |
586 | return; |
532 | 587 | ||
533 | dptr = (u8_t*)conf; |
588 | dptr = (u8_t*)conf; |
534 | dptr+= conf->bLength; |
589 | dptr+= conf->bLength; |
535 | 590 | ||
536 | dbgprintf("configuration descriptor\n\n" |
591 | dbgprintf("configuration descriptor\n\n" |
537 | "bLength %d\n" |
592 | "bLength %d\n" |
538 | "bDescriptorType %d\n" |
593 | "bDescriptorType %d\n" |
539 | "wTotalLength %d\n" |
594 | "wTotalLength %d\n" |
540 | "bNumInterfaces %d\n" |
595 | "bNumInterfaces %d\n" |
541 | "bConfigurationValue %x\n" |
596 | "bConfigurationValue %x\n" |
542 | "iConfiguration %d\n" |
597 | "iConfiguration %d\n" |
543 | "bmAttributes %x\n" |
598 | "bmAttributes %x\n" |
544 | "bMaxPower %dmA\n\n", |
599 | "bMaxPower %dmA\n\n", |
545 | conf->bLength, |
600 | conf->bLength, |
546 | conf->bDescriptorType, |
601 | conf->bDescriptorType, |
547 | conf->wTotalLength, |
602 | conf->wTotalLength, |
548 | conf->bNumInterfaces, |
603 | conf->bNumInterfaces, |
549 | conf->bConfigurationValue, |
604 | conf->bConfigurationValue, |
550 | conf->iConfiguration, |
605 | conf->iConfiguration, |
551 | conf->bmAttributes, |
606 | conf->bmAttributes, |
552 | conf->bMaxPower*2); |
607 | conf->bMaxPower*2); |
553 | 608 | ||
554 | interface = (interface_descr_t*)dptr; |
609 | interface = (interface_descr_t*)dptr; |
555 | 610 | ||
556 | switch(interface->bInterfaceClass) |
611 | switch(interface->bInterfaceClass) |
557 | { |
612 | { |
558 | case USB_CLASS_AUDIO: |
613 | case USB_CLASS_AUDIO: |
559 | dbgprintf( "audio device\n"); |
614 | dbgprintf( "audio device\n"); |
560 | break; |
615 | break; |
561 | case USB_CLASS_HID: |
616 | case USB_CLASS_HID: |
562 | dev->conf = conf; |
617 | dev->conf = conf; |
563 | list_del(&dev->list); |
618 | list_del(&dev->list); |
564 | return init_hid(dev); |
619 | return init_hid(dev); |
565 | 620 | ||
566 | case USB_CLASS_PRINTER: |
621 | case USB_CLASS_PRINTER: |
567 | dbgprintf("printer\n"); |
622 | dbgprintf("printer\n"); |
568 | break; |
623 | break; |
569 | case USB_CLASS_MASS_STORAGE: |
624 | case USB_CLASS_MASS_STORAGE: |
570 | dbgprintf("mass storage device\n"); |
625 | dbgprintf("mass storage device\n"); |
571 | break; |
626 | break; |
572 | case USB_CLASS_HUB: |
627 | case USB_CLASS_HUB: |
573 | dbgprintf("hub device\n"); |
628 | dbgprintf("hub device\n"); |
574 | break; |
629 | break; |
575 | default: |
630 | default: |
576 | dbgprintf("unknown device\n"); |
631 | dbgprintf("unknown device\n"); |
577 | }; |
632 | }; |
578 | };8)|pid; |
633 | };8)|pid; |
579 | ><8)|pid; |
634 | ><8)|pid; |
580 | >21)|DATA1|(dev-><21)|DATA1|(dev->>>><> |
635 | >21)|DATA1|(dev-><21)|DATA1|(dev->>>><> |
581 | > |
636 | > |
582 | >>>1024;>>6;i++) |
637 | >>>=>>23)><23)>24)><24)>>>>6;i++) |
583 | > |
638 | > |