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