]>
Commit | Line | Data |
---|---|---|
affae2bf | 1 | /* |
460c322f WD |
2 | * Part of this code has been derived from linux: |
3 | * Universal Host Controller Interface driver for USB (take II). | |
4 | * | |
5 | * (c) 1999-2001 Georg Acher, acher@in.tum.de (executive slave) (base guitar) | |
6 | * Deti Fliegl, deti@fliegl.de (executive slave) (lead voice) | |
7 | * Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader) | |
8 | * Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter) | |
9 | * (c) 2000 Yggdrasil Computing, Inc. (port of new PCI interface support | |
10 | * from usb-ohci.c by Adam Richter, adam@yggdrasil.com). | |
11 | * (C) 2000 David Brownell, david-b@pacbell.net (usb-ohci.c) | |
12 | * | |
13 | * HW-initalization based on material of | |
14 | * | |
15 | * (C) Copyright 1999 Linus Torvalds | |
16 | * (C) Copyright 1999 Johannes Erdfelt | |
17 | * (C) Copyright 1999 Randy Dunlap | |
18 | * (C) Copyright 1999 Gregory P. Smith | |
19 | * | |
20 | * | |
21 | * Adapted for U-Boot: | |
22 | * (C) Copyright 2001 Denis Peter, MPL AG Switzerland | |
affae2bf | 23 | * |
1a459660 | 24 | * SPDX-License-Identifier: GPL-2.0+ |
affae2bf WD |
25 | */ |
26 | ||
27 | /********************************************************************** | |
28 | * How it works: | |
29 | * ------------- | |
30 | * The framelist / Transfer descriptor / Queue Heads are similar like | |
31 | * in the linux usb_uhci.c. | |
32 | * | |
33 | * During initialization, the following skeleton is allocated in init_skel: | |
34 | * | |
35 | * framespecific | common chain | |
36 | * | |
37 | * framelist[] | |
38 | * [ 0 ]-----> TD ---------\ | |
39 | * [ 1 ]-----> TD ----------> TD ------> QH -------> QH -------> QH ---> NULL | |
40 | * ... TD ---------/ | |
41 | * [1023]-----> TD --------/ | |
42 | * | |
43 | * ^^ ^^ ^^ ^^ ^^ | |
44 | * 7 TDs for 1 TD for Start of Start of End Chain | |
45 | * INT (2-128ms) 1ms-INT CTRL Chain BULK Chain | |
46 | * | |
47 | * | |
48 | * Since this is a bootloader, the isochronous transfer descriptor have been removed. | |
49 | * | |
50 | * Interrupt Transfers. | |
51 | * -------------------- | |
16263087 | 52 | * For Interrupt transfers USB_MAX_TEMP_INT_TD Transfer descriptor are available. They |
affae2bf WD |
53 | * will be inserted after the appropriate (depending the interval setting) skeleton TD. |
54 | * If an interrupt has been detected the dev->irqhandler is called. The status and number | |
55 | * of transfered bytes is stored in dev->irq_status resp. dev->irq_act_len. If the | |
56 | * dev->irqhandler returns 0, the interrupt TD is removed and disabled. If an 1 is returned, | |
57 | * the interrupt TD will be reactivated. | |
58 | * | |
59 | * Control Transfers | |
60 | * ----------------- | |
61 | * Control Transfers are issued by filling the tmp_td with the appropriate data and connect | |
62 | * them to the qh_cntrl queue header. Before other control/bulk transfers can be issued, | |
63 | * the programm has to wait for completion. This does not allows asynchronous data transfer. | |
64 | * | |
65 | * Bulk Transfers | |
66 | * -------------- | |
67 | * Bulk Transfers are issued by filling the tmp_td with the appropriate data and connect | |
68 | * them to the qh_bulk queue header. Before other control/bulk transfers can be issued, | |
69 | * the programm has to wait for completion. This does not allows asynchronous data transfer. | |
70 | * | |
71 | * | |
72 | */ | |
73 | ||
74 | #include <common.h> | |
75 | #include <pci.h> | |
76 | ||
77 | #ifdef CONFIG_USB_UHCI | |
78 | ||
79 | #include <usb.h> | |
80 | #include "usb_uhci.h" | |
81 | ||
82 | #define USB_MAX_TEMP_TD 128 /* number of temporary TDs for bulk and control transfers */ | |
83 | #define USB_MAX_TEMP_INT_TD 32 /* number of temporary TDs for Interrupt transfers */ | |
84 | ||
85 | ||
86 | #undef USB_UHCI_DEBUG | |
87 | ||
88 | #ifdef USB_UHCI_DEBUG | |
89 | #define USB_UHCI_PRINTF(fmt,args...) printf (fmt ,##args) | |
90 | #else | |
91 | #define USB_UHCI_PRINTF(fmt,args...) | |
92 | #endif | |
93 | ||
94 | ||
95 | static int irqvec = -1; /* irq vector, if -1 uhci is stopped / reseted */ | |
96 | unsigned int usb_base_addr; /* base address */ | |
97 | ||
98 | static uhci_td_t td_int[8]; /* Interrupt Transfer descriptors */ | |
99 | static uhci_qh_t qh_cntrl; /* control Queue Head */ | |
100 | static uhci_qh_t qh_bulk; /* bulk Queue Head */ | |
101 | static uhci_qh_t qh_end; /* end Queue Head */ | |
102 | static uhci_td_t td_last; /* last TD (linked with end chain) */ | |
103 | ||
104 | /* temporary tds */ | |
105 | static uhci_td_t tmp_td[USB_MAX_TEMP_TD]; /* temporary bulk/control td's */ | |
106 | static uhci_td_t tmp_int_td[USB_MAX_TEMP_INT_TD]; /* temporary interrupt td's */ | |
107 | ||
108 | static unsigned long framelist[1024] __attribute__ ((aligned (0x1000))); /* frame list */ | |
109 | ||
110 | static struct virt_root_hub rh; /* struct for root hub */ | |
111 | ||
112 | /********************************************************************** | |
113 | * some forward decleration | |
114 | */ | |
115 | int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, | |
116 | void *buffer, int transfer_len,struct devrequest *setup); | |
117 | ||
118 | /* fill a td with the approproiate data. Link, status, info and buffer | |
119 | * are used by the USB controller itselfes, dev is used to identify the | |
120 | * "connected" device | |
121 | */ | |
122 | void usb_fill_td(uhci_td_t* td,unsigned long link,unsigned long status, | |
123 | unsigned long info, unsigned long buffer, unsigned long dev) | |
124 | { | |
125 | td->link=swap_32(link); | |
126 | td->status=swap_32(status); | |
127 | td->info=swap_32(info); | |
128 | td->buffer=swap_32(buffer); | |
129 | td->dev_ptr=dev; | |
130 | } | |
131 | ||
132 | /* fill a qh with the approproiate data. Head and element are used by the USB controller | |
133 | * itselfes. As soon as a valid dev_ptr is filled, a td chain is connected to the qh. | |
134 | * Please note, that after completion of the td chain, the entry element is removed / | |
135 | * marked invalid by the USB controller. | |
136 | */ | |
137 | void usb_fill_qh(uhci_qh_t* qh,unsigned long head,unsigned long element) | |
138 | { | |
139 | qh->head=swap_32(head); | |
140 | qh->element=swap_32(element); | |
141 | qh->dev_ptr=0L; | |
142 | } | |
143 | ||
144 | /* get the status of a td->status | |
145 | */ | |
146 | unsigned long usb_uhci_td_stat(unsigned long status) | |
147 | { | |
148 | unsigned long result=0; | |
149 | result |= (status & TD_CTRL_NAK) ? USB_ST_NAK_REC : 0; | |
150 | result |= (status & TD_CTRL_STALLED) ? USB_ST_STALLED : 0; | |
151 | result |= (status & TD_CTRL_DBUFERR) ? USB_ST_BUF_ERR : 0; | |
152 | result |= (status & TD_CTRL_BABBLE) ? USB_ST_BABBLE_DET : 0; | |
153 | result |= (status & TD_CTRL_CRCTIMEO) ? USB_ST_CRC_ERR : 0; | |
154 | result |= (status & TD_CTRL_BITSTUFF) ? USB_ST_BIT_ERR : 0; | |
155 | result |= (status & TD_CTRL_ACTIVE) ? USB_ST_NOT_PROC : 0; | |
156 | return result; | |
157 | } | |
158 | ||
159 | /* get the status and the transfered len of a td chain. | |
160 | * called from the completion handler | |
161 | */ | |
162 | int usb_get_td_status(uhci_td_t *td,struct usb_device *dev) | |
163 | { | |
164 | unsigned long temp,info; | |
165 | unsigned long stat; | |
166 | uhci_td_t *mytd=td; | |
167 | ||
168 | if(dev->devnum==rh.devnum) | |
169 | return 0; | |
170 | dev->act_len=0; | |
171 | stat=0; | |
172 | do { | |
173 | temp=swap_32((unsigned long)mytd->status); | |
174 | stat=usb_uhci_td_stat(temp); | |
175 | info=swap_32((unsigned long)mytd->info); | |
176 | if(((info & 0xff)!= USB_PID_SETUP) && | |
177 | (((info >> 21) & 0x7ff)!= 0x7ff) && | |
178 | (temp & 0x7FF)!=0x7ff) | |
179 | { /* if not setup and not null data pack */ | |
180 | dev->act_len+=(temp & 0x7FF) + 1; /* the transfered len is act_len + 1 */ | |
181 | } | |
182 | if(stat) { /* status no ok */ | |
183 | dev->status=stat; | |
184 | return -1; | |
185 | } | |
186 | temp=swap_32((unsigned long)mytd->link); | |
187 | mytd=(uhci_td_t *)(temp & 0xfffffff0); | |
188 | }while((temp & 0x1)==0); /* process all TDs */ | |
189 | dev->status=stat; | |
190 | return 0; /* Ok */ | |
191 | } | |
192 | ||
193 | ||
194 | /*------------------------------------------------------------------- | |
195 | * LOW LEVEL STUFF | |
196 | * assembles QHs und TDs for control, bulk and iso | |
197 | *-------------------------------------------------------------------*/ | |
198 | ||
199 | /* Submits a control message. That is a Setup, Data and Status transfer. | |
200 | * Routine does not wait for completion. | |
201 | */ | |
202 | int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, | |
203 | int transfer_len,struct devrequest *setup) | |
204 | { | |
205 | unsigned long destination, status; | |
206 | int maxsze = usb_maxpacket(dev, pipe); | |
207 | unsigned long dataptr; | |
208 | int len; | |
209 | int pktsze; | |
210 | int i=0; | |
211 | ||
212 | if (!maxsze) { | |
213 | USB_UHCI_PRINTF("uhci_submit_control_urb: pipesize for pipe %lx is zero\n", pipe); | |
214 | return -1; | |
215 | } | |
216 | if(((pipe>>8)&0x7f)==rh.devnum) { | |
217 | /* this is the root hub -> redirect it */ | |
218 | return uhci_submit_rh_msg(dev,pipe,buffer,transfer_len,setup); | |
219 | } | |
220 | USB_UHCI_PRINTF("uhci_submit_control start len %x, maxsize %x\n",transfer_len,maxsze); | |
221 | /* The "pipe" thing contains the destination in bits 8--18 */ | |
222 | destination = (pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; /* Setup stage */ | |
223 | /* 3 errors */ | |
224 | status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27); | |
225 | /* (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD); */ | |
226 | /* Build the TD for the control request, try forever, 8 bytes of data */ | |
227 | usb_fill_td(&tmp_td[i],UHCI_PTR_TERM ,status, destination | (7 << 21),(unsigned long)setup,(unsigned long)dev); | |
228 | #if 0 | |
229 | { | |
230 | char *sp=(char *)setup; | |
231 | printf("SETUP to pipe %lx: %x %x %x %x %x %x %x %x\n", pipe, | |
232 | sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]); | |
233 | } | |
234 | #endif | |
235 | dataptr = (unsigned long)buffer; | |
236 | len=transfer_len; | |
237 | ||
238 | /* If direction is "send", change the frame from SETUP (0x2D) | |
239 | to OUT (0xE1). Else change it from SETUP to IN (0x69). */ | |
240 | destination = (pipe & PIPE_DEVEP_MASK) | ((pipe & USB_DIR_IN)==0 ? USB_PID_OUT : USB_PID_IN); | |
241 | while (len > 0) { | |
242 | /* data stage */ | |
243 | pktsze = len; | |
244 | i++; | |
245 | if (pktsze > maxsze) | |
246 | pktsze = maxsze; | |
247 | destination ^= 1 << TD_TOKEN_TOGGLE; /* toggle DATA0/1 */ | |
248 | usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status, destination | ((pktsze - 1) << 21),dataptr,(unsigned long)dev); /* Status, pktsze bytes of data */ | |
249 | tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]); | |
250 | ||
251 | dataptr += pktsze; | |
252 | len -= pktsze; | |
253 | } | |
254 | ||
255 | /* Build the final TD for control status */ | |
256 | /* It's only IN if the pipe is out AND we aren't expecting data */ | |
257 | ||
258 | destination &= ~UHCI_PID; | |
259 | if (((pipe & USB_DIR_IN)==0) || (transfer_len == 0)) | |
260 | destination |= USB_PID_IN; | |
261 | else | |
262 | destination |= USB_PID_OUT; | |
263 | destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */ | |
264 | i++; | |
265 | status &=~TD_CTRL_SPD; | |
266 | /* no limit on errors on final packet , 0 bytes of data */ | |
267 | usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),0,(unsigned long)dev); | |
268 | tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]); /* queue status td */ | |
269 | /* usb_show_td(i+1);*/ | |
270 | USB_UHCI_PRINTF("uhci_submit_control end (%d tmp_tds used)\n",i); | |
271 | /* first mark the control QH element terminated */ | |
272 | qh_cntrl.element=0xffffffffL; | |
273 | /* set qh active */ | |
274 | qh_cntrl.dev_ptr=(unsigned long)dev; | |
275 | /* fill in tmp_td_chain */ | |
276 | qh_cntrl.element=swap_32((unsigned long)&tmp_td[0]); | |
277 | return 0; | |
278 | } | |
279 | ||
280 | /*------------------------------------------------------------------- | |
281 | * Prepare TDs for bulk transfers. | |
282 | */ | |
283 | int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len) | |
284 | { | |
285 | unsigned long destination, status,info; | |
286 | unsigned long dataptr; | |
287 | int maxsze = usb_maxpacket(dev, pipe); | |
288 | int len; | |
289 | int i=0; | |
290 | ||
291 | if(transfer_len < 0) { | |
292 | printf("Negative transfer length in submit_bulk\n"); | |
293 | return -1; | |
294 | } | |
295 | if (!maxsze) | |
296 | return -1; | |
297 | /* The "pipe" thing contains the destination in bits 8--18. */ | |
298 | destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe); | |
299 | /* 3 errors */ | |
300 | status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27); | |
301 | /* ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27); */ | |
302 | /* Build the TDs for the bulk request */ | |
303 | len = transfer_len; | |
304 | dataptr = (unsigned long)buffer; | |
305 | do { | |
306 | int pktsze = len; | |
307 | if (pktsze > maxsze) | |
308 | pktsze = maxsze; | |
309 | /* pktsze bytes of data */ | |
310 | info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) | | |
311 | (usb_gettoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE); | |
312 | ||
313 | if((len-pktsze)==0) | |
314 | status |= TD_CTRL_IOC; /* last one generates INT */ | |
315 | ||
316 | usb_fill_td(&tmp_td[i],UHCI_PTR_TERM, status, info,dataptr,(unsigned long)dev); /* Status, pktsze bytes of data */ | |
317 | if(i>0) | |
318 | tmp_td[i-1].link=swap_32((unsigned long)&tmp_td[i]); | |
319 | i++; | |
320 | dataptr += pktsze; | |
321 | len -= pktsze; | |
322 | usb_dotoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)); | |
323 | } while (len > 0); | |
324 | /* first mark the bulk QH element terminated */ | |
325 | qh_bulk.element=0xffffffffL; | |
326 | /* set qh active */ | |
327 | qh_bulk.dev_ptr=(unsigned long)dev; | |
328 | /* fill in tmp_td_chain */ | |
329 | qh_bulk.element=swap_32((unsigned long)&tmp_td[0]); | |
330 | return 0; | |
331 | } | |
332 | ||
333 | ||
334 | /* search a free interrupt td | |
335 | */ | |
336 | uhci_td_t *uhci_alloc_int_td(void) | |
337 | { | |
338 | int i; | |
339 | for(i=0;i<USB_MAX_TEMP_INT_TD;i++) { | |
340 | if(tmp_int_td[i].dev_ptr==0) /* no device assigned -> free TD */ | |
341 | return &tmp_int_td[i]; | |
342 | } | |
343 | return NULL; | |
344 | } | |
345 | ||
346 | #if 0 | |
347 | void uhci_show_temp_int_td(void) | |
348 | { | |
349 | int i; | |
350 | for(i=0;i<USB_MAX_TEMP_INT_TD;i++) { | |
351 | if((tmp_int_td[i].dev_ptr&0x01)!=0x1L) /* no device assigned -> free TD */ | |
352 | printf("temp_td %d is assigned to dev %lx\n",i,tmp_int_td[i].dev_ptr); | |
353 | } | |
354 | printf("all others temp_tds are free\n"); | |
355 | } | |
356 | #endif | |
357 | /*------------------------------------------------------------------- | |
358 | * submits USB interrupt (ie. polling ;-) | |
359 | */ | |
360 | int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len, int interval) | |
361 | { | |
362 | int nint, n; | |
363 | unsigned long status, destination; | |
364 | unsigned long info,tmp; | |
365 | uhci_td_t *mytd; | |
366 | if (interval < 0 || interval >= 256) | |
367 | return -1; | |
368 | ||
369 | if (interval == 0) | |
370 | nint = 0; | |
371 | else { | |
372 | for (nint = 0, n = 1; nint <= 8; nint++, n += n) /* round interval down to 2^n */ | |
373 | { | |
374 | if(interval < n) { | |
375 | interval = n / 2; | |
376 | break; | |
377 | } | |
378 | } | |
379 | nint--; | |
380 | } | |
381 | ||
382 | USB_UHCI_PRINTF("Rounded interval to %i, chain %i\n", interval, nint); | |
383 | mytd=uhci_alloc_int_td(); | |
384 | if(mytd==NULL) { | |
385 | printf("No free INT TDs found\n"); | |
386 | return -1; | |
387 | } | |
388 | status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | (3 << 27); | |
389 | /* (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); | |
390 | */ | |
391 | ||
392 | destination =(pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe) | (((transfer_len - 1) & 0x7ff) << 21); | |
393 | ||
394 | info = destination | (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); | |
395 | tmp = swap_32(td_int[nint].link); | |
396 | usb_fill_td(mytd,tmp,status, info,(unsigned long)buffer,(unsigned long)dev); | |
397 | /* Link it */ | |
398 | tmp = swap_32((unsigned long)mytd); | |
399 | td_int[nint].link=tmp; | |
400 | ||
401 | usb_dotoggle (dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)); | |
402 | ||
403 | return 0; | |
404 | } | |
405 | ||
406 | /********************************************************************** | |
407 | * Low Level functions | |
408 | */ | |
409 | ||
410 | ||
411 | void reset_hc(void) | |
412 | { | |
413 | ||
414 | /* Global reset for 100ms */ | |
415 | out16r( usb_base_addr + USBPORTSC1,0x0204); | |
416 | out16r( usb_base_addr + USBPORTSC2,0x0204); | |
417 | out16r( usb_base_addr + USBCMD,USBCMD_GRESET | USBCMD_RS); | |
418 | /* Turn off all interrupts */ | |
419 | out16r(usb_base_addr + USBINTR,0); | |
5b84dd67 | 420 | mdelay(50); |
affae2bf | 421 | out16r( usb_base_addr + USBCMD,0); |
5b84dd67 | 422 | mdelay(10); |
affae2bf WD |
423 | } |
424 | ||
425 | void start_hc(void) | |
426 | { | |
427 | int timeout = 1000; | |
428 | ||
429 | while(in16r(usb_base_addr + USBCMD) & USBCMD_HCRESET) { | |
430 | if (!--timeout) { | |
431 | printf("USBCMD_HCRESET timed out!\n"); | |
432 | break; | |
433 | } | |
434 | } | |
435 | /* Turn on all interrupts */ | |
436 | out16r(usb_base_addr + USBINTR,USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP); | |
437 | /* Start at frame 0 */ | |
438 | out16r(usb_base_addr + USBFRNUM,0); | |
439 | /* set Framebuffer base address */ | |
440 | out32r(usb_base_addr+USBFLBASEADD,(unsigned long)&framelist); | |
441 | /* Run and mark it configured with a 64-byte max packet */ | |
442 | out16r(usb_base_addr + USBCMD,USBCMD_RS | USBCMD_CF | USBCMD_MAXP); | |
443 | } | |
444 | ||
445 | /* Initialize the skeleton | |
446 | */ | |
447 | void usb_init_skel(void) | |
448 | { | |
449 | unsigned long temp; | |
450 | int n; | |
451 | ||
452 | for(n=0;n<USB_MAX_TEMP_INT_TD;n++) | |
453 | tmp_int_td[n].dev_ptr=0L; /* no devices connected */ | |
454 | /* last td */ | |
455 | usb_fill_td(&td_last,UHCI_PTR_TERM,TD_CTRL_IOC ,0,0,0L); | |
456 | /* usb_fill_td(&td_last,UHCI_PTR_TERM,0,0,0); */ | |
457 | /* End Queue Header */ | |
458 | usb_fill_qh(&qh_end,UHCI_PTR_TERM,(unsigned long)&td_last); | |
459 | /* Bulk Queue Header */ | |
460 | temp=(unsigned long)&qh_end; | |
461 | usb_fill_qh(&qh_bulk,temp | UHCI_PTR_QH,UHCI_PTR_TERM); | |
462 | /* Control Queue Header */ | |
463 | temp=(unsigned long)&qh_bulk; | |
464 | usb_fill_qh(&qh_cntrl, temp | UHCI_PTR_QH,UHCI_PTR_TERM); | |
465 | /* 1ms Interrupt td */ | |
466 | temp=(unsigned long)&qh_cntrl; | |
467 | usb_fill_td(&td_int[0],temp | UHCI_PTR_QH,0,0,0,0L); | |
468 | temp=(unsigned long)&td_int[0]; | |
469 | for(n=1; n<8; n++) | |
470 | usb_fill_td(&td_int[n],temp,0,0,0,0L); | |
471 | for (n = 0; n < 1024; n++) { | |
472 | /* link all framelist pointers to one of the interrupts */ | |
473 | int m, o; | |
474 | if ((n&127)==127) | |
475 | framelist[n]= swap_32((unsigned long)&td_int[0]); | |
476 | else | |
477 | for (o = 1, m = 2; m <= 128; o++, m += m) | |
478 | if ((n & (m - 1)) == ((m - 1) / 2)) | |
479 | framelist[n]= swap_32((unsigned long)&td_int[o]); | |
480 | } | |
481 | } | |
482 | ||
483 | /* check the common skeleton for completed transfers, and update the status | |
484 | * of the "connected" device. Called from the IRQ routine. | |
485 | */ | |
486 | void usb_check_skel(void) | |
487 | { | |
488 | struct usb_device *dev; | |
489 | /* start with the control qh */ | |
490 | if(qh_cntrl.dev_ptr!=0) /* it's a device assigned check if this caused IRQ */ | |
491 | { | |
492 | dev=(struct usb_device *)qh_cntrl.dev_ptr; | |
493 | usb_get_td_status(&tmp_td[0],dev); /* update status */ | |
494 | if(!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */ | |
495 | qh_cntrl.dev_ptr=0; | |
496 | } | |
497 | } | |
498 | /* now process the bulk */ | |
499 | if(qh_bulk.dev_ptr!=0) /* it's a device assigned check if this caused IRQ */ | |
500 | { | |
501 | dev=(struct usb_device *)qh_bulk.dev_ptr; | |
502 | usb_get_td_status(&tmp_td[0],dev); /* update status */ | |
503 | if(!(dev->status & USB_ST_NOT_PROC)) { /* is not active anymore, disconnect devices */ | |
504 | qh_bulk.dev_ptr=0; | |
505 | } | |
506 | } | |
507 | } | |
508 | ||
509 | /* check the interrupt chain, ubdate the status of the appropriate device, | |
510 | * call the appropriate irqhandler and reactivate the TD if the irqhandler | |
511 | * returns with 1 | |
512 | */ | |
513 | void usb_check_int_chain(void) | |
514 | { | |
515 | int i,res; | |
516 | unsigned long link,status; | |
517 | struct usb_device *dev; | |
518 | uhci_td_t *td,*prevtd; | |
519 | ||
520 | for(i=0;i<8;i++) { | |
d0ff51ba | 521 | prevtd = &td_int[i]; /* the first previous td is the skeleton td */ |
affae2bf WD |
522 | link=swap_32(td_int[i].link) & 0xfffffff0; /* next in chain */ |
523 | td=(uhci_td_t *)link; /* assign it */ | |
524 | /* all interrupt TDs are finally linked to the td_int[0]. | |
53677ef1 | 525 | * so we process all until we find the td_int[0]. |
affae2bf WD |
526 | * if int0 chain points to a QH, we're also done |
527 | */ | |
528 | while(((i>0) && (link != (unsigned long)&td_int[0])) || | |
529 | ((i==0) && !(swap_32(td->link) & UHCI_PTR_QH))) | |
530 | { | |
531 | /* check if a device is assigned with this td */ | |
532 | status=swap_32(td->status); | |
533 | if((td->dev_ptr!=0L) && !(status & TD_CTRL_ACTIVE)) { | |
534 | /* td is not active and a device is assigned -> call irqhandler */ | |
535 | dev=(struct usb_device *)td->dev_ptr; | |
536 | dev->irq_act_len=((status & 0x7FF)==0x7FF) ? 0 : (status & 0x7FF) + 1; /* transfered length */ | |
537 | dev->irq_status=usb_uhci_td_stat(status); /* get status */ | |
538 | res=dev->irq_handle(dev); /* call irqhandler */ | |
539 | if(res==1) { | |
540 | /* reactivate */ | |
541 | status|=TD_CTRL_ACTIVE; | |
542 | td->status=swap_32(status); | |
543 | prevtd=td; /* previous td = this td */ | |
544 | } | |
545 | else { | |
546 | prevtd->link=td->link; /* link previous td directly to the nex td -> unlinked */ | |
547 | /* remove device pointer */ | |
548 | td->dev_ptr=0L; | |
549 | } | |
550 | } /* if we call the irq handler */ | |
551 | link=swap_32(td->link) & 0xfffffff0; /* next in chain */ | |
552 | td=(uhci_td_t *)link; /* assign it */ | |
553 | } /* process all td in this int chain */ | |
554 | } /* next interrupt chain */ | |
555 | } | |
556 | ||
557 | ||
558 | /* usb interrupt service routine. | |
559 | */ | |
560 | void handle_usb_interrupt(void) | |
561 | { | |
562 | unsigned short status; | |
563 | ||
564 | /* | |
565 | * Read the interrupt status, and write it back to clear the | |
566 | * interrupt cause | |
567 | */ | |
568 | ||
569 | status = in16r(usb_base_addr + USBSTS); | |
570 | ||
571 | if (!status) /* shared interrupt, not mine */ | |
572 | return; | |
573 | if (status != 1) { | |
574 | /* remove host controller halted state */ | |
575 | if ((status&0x20) && ((in16r(usb_base_addr+USBCMD) && USBCMD_RS)==0)) { | |
576 | out16r(usb_base_addr + USBCMD, USBCMD_RS | in16r(usb_base_addr + USBCMD)); | |
577 | } | |
578 | } | |
579 | usb_check_int_chain(); /* call interrupt handlers for int tds */ | |
580 | usb_check_skel(); /* call completion handler for common transfer routines */ | |
581 | out16r(usb_base_addr+USBSTS,status); | |
582 | } | |
583 | ||
584 | ||
585 | /* init uhci | |
586 | */ | |
c7e3b2b5 | 587 | int usb_lowlevel_init(int index, void **controller) |
affae2bf WD |
588 | { |
589 | unsigned char temp; | |
590 | int busdevfunc; | |
591 | ||
592 | busdevfunc=pci_find_device(USB_UHCI_VEND_ID,USB_UHCI_DEV_ID,0); /* get PCI Device ID */ | |
593 | if(busdevfunc==-1) { | |
594 | printf("Error USB UHCI (%04X,%04X) not found\n",USB_UHCI_VEND_ID,USB_UHCI_DEV_ID); | |
595 | return -1; | |
596 | } | |
597 | pci_read_config_byte(busdevfunc,PCI_INTERRUPT_LINE,&temp); | |
598 | irqvec = temp; | |
599 | irq_free_handler(irqvec); | |
600 | USB_UHCI_PRINTF("Interrupt Line = %d, is %d\n",irqvec); | |
601 | pci_read_config_byte(busdevfunc,PCI_INTERRUPT_PIN,&temp); | |
602 | USB_UHCI_PRINTF("Interrupt Pin = %ld\n",temp); | |
603 | pci_read_config_dword(busdevfunc,PCI_BASE_ADDRESS_4,&usb_base_addr); | |
604 | USB_UHCI_PRINTF("IO Base Address = 0x%lx\n",usb_base_addr); | |
605 | usb_base_addr&=0xFFFFFFF0; | |
6d0f6bcf | 606 | usb_base_addr+=CONFIG_SYS_ISA_IO_BASE_ADDRESS; |
affae2bf WD |
607 | rh.devnum = 0; |
608 | usb_init_skel(); | |
609 | reset_hc(); | |
610 | start_hc(); | |
611 | irq_install_handler(irqvec, (interrupt_handler_t *)handle_usb_interrupt, NULL); | |
612 | return 0; | |
613 | } | |
614 | ||
615 | /* stop uhci | |
616 | */ | |
c7e3b2b5 | 617 | int usb_lowlevel_stop(int index) |
affae2bf WD |
618 | { |
619 | if(irqvec==-1) | |
620 | return 1; | |
621 | irq_free_handler(irqvec); | |
622 | reset_hc(); | |
d0ff51ba | 623 | irqvec = -1; |
affae2bf WD |
624 | return 0; |
625 | } | |
626 | ||
627 | /******************************************************************************************* | |
628 | * Virtual Root Hub | |
629 | * Since the uhci does not have a real HUB, we simulate one ;-) | |
630 | */ | |
631 | #undef USB_RH_DEBUG | |
632 | ||
633 | #ifdef USB_RH_DEBUG | |
634 | #define USB_RH_PRINTF(fmt,args...) printf (fmt ,##args) | |
635 | static void usb_display_wValue(unsigned short wValue,unsigned short wIndex); | |
636 | static void usb_display_Req(unsigned short req); | |
637 | #else | |
638 | #define USB_RH_PRINTF(fmt,args...) | |
639 | static void usb_display_wValue(unsigned short wValue,unsigned short wIndex) {} | |
640 | static void usb_display_Req(unsigned short req) {} | |
641 | #endif | |
642 | ||
643 | static unsigned char root_hub_dev_des[] = | |
644 | { | |
645 | 0x12, /* __u8 bLength; */ | |
646 | 0x01, /* __u8 bDescriptorType; Device */ | |
647 | 0x00, /* __u16 bcdUSB; v1.0 */ | |
648 | 0x01, | |
649 | 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ | |
650 | 0x00, /* __u8 bDeviceSubClass; */ | |
651 | 0x00, /* __u8 bDeviceProtocol; */ | |
652 | 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ | |
653 | 0x00, /* __u16 idVendor; */ | |
654 | 0x00, | |
655 | 0x00, /* __u16 idProduct; */ | |
656 | 0x00, | |
657 | 0x00, /* __u16 bcdDevice; */ | |
658 | 0x00, | |
659 | 0x01, /* __u8 iManufacturer; */ | |
660 | 0x00, /* __u8 iProduct; */ | |
661 | 0x00, /* __u8 iSerialNumber; */ | |
662 | 0x01 /* __u8 bNumConfigurations; */ | |
663 | }; | |
664 | ||
665 | ||
666 | /* Configuration descriptor */ | |
667 | static unsigned char root_hub_config_des[] = | |
668 | { | |
669 | 0x09, /* __u8 bLength; */ | |
670 | 0x02, /* __u8 bDescriptorType; Configuration */ | |
671 | 0x19, /* __u16 wTotalLength; */ | |
672 | 0x00, | |
673 | 0x01, /* __u8 bNumInterfaces; */ | |
674 | 0x01, /* __u8 bConfigurationValue; */ | |
675 | 0x00, /* __u8 iConfiguration; */ | |
676 | 0x40, /* __u8 bmAttributes; | |
677 | Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ | |
678 | 0x00, /* __u8 MaxPower; */ | |
679 | ||
680 | /* interface */ | |
681 | 0x09, /* __u8 if_bLength; */ | |
682 | 0x04, /* __u8 if_bDescriptorType; Interface */ | |
683 | 0x00, /* __u8 if_bInterfaceNumber; */ | |
684 | 0x00, /* __u8 if_bAlternateSetting; */ | |
685 | 0x01, /* __u8 if_bNumEndpoints; */ | |
686 | 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ | |
687 | 0x00, /* __u8 if_bInterfaceSubClass; */ | |
688 | 0x00, /* __u8 if_bInterfaceProtocol; */ | |
689 | 0x00, /* __u8 if_iInterface; */ | |
690 | ||
691 | /* endpoint */ | |
692 | 0x07, /* __u8 ep_bLength; */ | |
693 | 0x05, /* __u8 ep_bDescriptorType; Endpoint */ | |
694 | 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ | |
695 | 0x03, /* __u8 ep_bmAttributes; Interrupt */ | |
696 | 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ | |
697 | 0x00, | |
698 | 0xff /* __u8 ep_bInterval; 255 ms */ | |
699 | }; | |
700 | ||
701 | ||
702 | static unsigned char root_hub_hub_des[] = | |
703 | { | |
704 | 0x09, /* __u8 bLength; */ | |
705 | 0x29, /* __u8 bDescriptorType; Hub-descriptor */ | |
706 | 0x02, /* __u8 bNbrPorts; */ | |
707 | 0x00, /* __u16 wHubCharacteristics; */ | |
708 | 0x00, | |
709 | 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ | |
710 | 0x00, /* __u8 bHubContrCurrent; 0 mA */ | |
711 | 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ | |
712 | 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ | |
713 | }; | |
714 | ||
715 | static unsigned char root_hub_str_index0[] = | |
716 | { | |
717 | 0x04, /* __u8 bLength; */ | |
718 | 0x03, /* __u8 bDescriptorType; String-descriptor */ | |
719 | 0x09, /* __u8 lang ID */ | |
720 | 0x04, /* __u8 lang ID */ | |
721 | }; | |
722 | ||
723 | static unsigned char root_hub_str_index1[] = | |
724 | { | |
725 | 28, /* __u8 bLength; */ | |
726 | 0x03, /* __u8 bDescriptorType; String-descriptor */ | |
727 | 'U', /* __u8 Unicode */ | |
728 | 0, /* __u8 Unicode */ | |
729 | 'H', /* __u8 Unicode */ | |
730 | 0, /* __u8 Unicode */ | |
731 | 'C', /* __u8 Unicode */ | |
732 | 0, /* __u8 Unicode */ | |
733 | 'I', /* __u8 Unicode */ | |
734 | 0, /* __u8 Unicode */ | |
735 | ' ', /* __u8 Unicode */ | |
736 | 0, /* __u8 Unicode */ | |
737 | 'R', /* __u8 Unicode */ | |
738 | 0, /* __u8 Unicode */ | |
739 | 'o', /* __u8 Unicode */ | |
740 | 0, /* __u8 Unicode */ | |
741 | 'o', /* __u8 Unicode */ | |
742 | 0, /* __u8 Unicode */ | |
743 | 't', /* __u8 Unicode */ | |
744 | 0, /* __u8 Unicode */ | |
745 | ' ', /* __u8 Unicode */ | |
746 | 0, /* __u8 Unicode */ | |
747 | 'H', /* __u8 Unicode */ | |
748 | 0, /* __u8 Unicode */ | |
749 | 'u', /* __u8 Unicode */ | |
750 | 0, /* __u8 Unicode */ | |
751 | 'b', /* __u8 Unicode */ | |
752 | 0, /* __u8 Unicode */ | |
753 | }; | |
754 | ||
755 | ||
756 | /* | |
757 | * Root Hub Control Pipe (interrupt Pipes are not supported) | |
758 | */ | |
759 | ||
760 | ||
761 | int uhci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len,struct devrequest *cmd) | |
762 | { | |
763 | void *data = buffer; | |
764 | int leni = transfer_len; | |
765 | int len = 0; | |
766 | int status = 0; | |
767 | int stat = 0; | |
768 | int i; | |
769 | ||
770 | unsigned short cstatus; | |
771 | ||
772 | unsigned short bmRType_bReq; | |
773 | unsigned short wValue; | |
774 | unsigned short wIndex; | |
775 | unsigned short wLength; | |
776 | ||
9dbc3667 | 777 | if (usb_pipeint(pipe)) { |
affae2bf WD |
778 | printf("Root-Hub submit IRQ: NOT implemented\n"); |
779 | #if 0 | |
780 | uhci->rh.urb = urb; | |
781 | uhci->rh.send = 1; | |
782 | uhci->rh.interval = urb->interval; | |
783 | rh_init_int_timer (urb); | |
784 | #endif | |
785 | return 0; | |
786 | } | |
787 | bmRType_bReq = cmd->requesttype | cmd->request << 8; | |
788 | wValue = swap_16(cmd->value); | |
789 | wIndex = swap_16(cmd->index); | |
790 | wLength = swap_16(cmd->length); | |
791 | usb_display_Req(bmRType_bReq); | |
792 | for (i = 0; i < 8; i++) | |
793 | rh.c_p_r[i] = 0; | |
794 | USB_RH_PRINTF("Root-Hub: adr: %2x cmd(%1x): %02x%02x %04x %04x %04x\n", | |
795 | dev->devnum, 8, cmd->requesttype,cmd->request, wValue, wIndex, wLength); | |
796 | ||
797 | switch (bmRType_bReq) { | |
798 | /* Request Destination: | |
799 | without flags: Device, | |
800 | RH_INTERFACE: interface, | |
801 | RH_ENDPOINT: endpoint, | |
802 | RH_CLASS means HUB here, | |
803 | RH_OTHER | RH_CLASS almost ever means HUB_PORT here | |
804 | */ | |
805 | ||
806 | case RH_GET_STATUS: | |
807 | *(unsigned short *) data = swap_16(1); | |
808 | len=2; | |
809 | break; | |
810 | case RH_GET_STATUS | RH_INTERFACE: | |
811 | *(unsigned short *) data = swap_16(0); | |
812 | len=2; | |
813 | break; | |
814 | case RH_GET_STATUS | RH_ENDPOINT: | |
815 | *(unsigned short *) data = swap_16(0); | |
816 | len=2; | |
817 | break; | |
818 | case RH_GET_STATUS | RH_CLASS: | |
819 | *(unsigned long *) data = swap_32(0); | |
820 | len=4; | |
821 | break; /* hub power ** */ | |
822 | case RH_GET_STATUS | RH_OTHER | RH_CLASS: | |
823 | ||
824 | status = in16r(usb_base_addr + USBPORTSC1 + 2 * (wIndex - 1)); | |
825 | cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) | | |
826 | ((status & USBPORTSC_PEC) >> (3 - 1)) | | |
827 | (rh.c_p_r[wIndex - 1] << (0 + 4)); | |
828 | status = (status & USBPORTSC_CCS) | | |
829 | ((status & USBPORTSC_PE) >> (2 - 1)) | | |
830 | ((status & USBPORTSC_SUSP) >> (12 - 2)) | | |
831 | ((status & USBPORTSC_PR) >> (9 - 4)) | | |
832 | (1 << 8) | /* power on ** */ | |
833 | ((status & USBPORTSC_LSDA) << (-8 + 9)); | |
834 | ||
835 | *(unsigned short *) data = swap_16(status); | |
836 | *(unsigned short *) (data + 2) = swap_16(cstatus); | |
837 | len=4; | |
838 | break; | |
839 | case RH_CLEAR_FEATURE | RH_ENDPOINT: | |
840 | switch (wValue) { | |
841 | case (RH_ENDPOINT_STALL): | |
842 | len=0; | |
843 | break; | |
844 | } | |
845 | break; | |
846 | ||
847 | case RH_CLEAR_FEATURE | RH_CLASS: | |
848 | switch (wValue) { | |
849 | case (RH_C_HUB_OVER_CURRENT): | |
850 | len=0; /* hub power over current ** */ | |
851 | break; | |
852 | } | |
853 | break; | |
854 | ||
855 | case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: | |
856 | usb_display_wValue(wValue,wIndex); | |
857 | switch (wValue) { | |
858 | case (RH_PORT_ENABLE): | |
859 | status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1)); | |
860 | status = (status & 0xfff5) & ~USBPORTSC_PE; | |
861 | out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status); | |
862 | len=0; | |
863 | break; | |
864 | case (RH_PORT_SUSPEND): | |
865 | status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1)); | |
866 | status = (status & 0xfff5) & ~USBPORTSC_SUSP; | |
867 | out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status); | |
868 | len=0; | |
869 | break; | |
870 | case (RH_PORT_POWER): | |
871 | len=0; /* port power ** */ | |
872 | break; | |
873 | case (RH_C_PORT_CONNECTION): | |
874 | status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1)); | |
875 | status = (status & 0xfff5) | USBPORTSC_CSC; | |
876 | out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status); | |
877 | len=0; | |
878 | break; | |
879 | case (RH_C_PORT_ENABLE): | |
880 | status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1)); | |
881 | status = (status & 0xfff5) | USBPORTSC_PEC; | |
882 | out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status); | |
883 | len=0; | |
884 | break; | |
885 | case (RH_C_PORT_SUSPEND): | |
886 | /*** WR_RH_PORTSTAT(RH_PS_PSSC); */ | |
887 | len=0; | |
888 | break; | |
889 | case (RH_C_PORT_OVER_CURRENT): | |
890 | len=0; | |
891 | break; | |
892 | case (RH_C_PORT_RESET): | |
893 | rh.c_p_r[wIndex - 1] = 0; | |
894 | len=0; | |
895 | break; | |
896 | } | |
897 | break; | |
898 | case RH_SET_FEATURE | RH_OTHER | RH_CLASS: | |
899 | usb_display_wValue(wValue,wIndex); | |
900 | switch (wValue) { | |
901 | case (RH_PORT_SUSPEND): | |
902 | status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1)); | |
903 | status = (status & 0xfff5) | USBPORTSC_SUSP; | |
904 | out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status); | |
905 | len=0; | |
906 | break; | |
907 | case (RH_PORT_RESET): | |
908 | status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1)); | |
909 | status = (status & 0xfff5) | USBPORTSC_PR; | |
910 | out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status); | |
5b84dd67 | 911 | mdelay(10); |
affae2bf WD |
912 | status = (status & 0xfff5) & ~USBPORTSC_PR; |
913 | out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status); | |
914 | udelay(10); | |
915 | status = (status & 0xfff5) | USBPORTSC_PE; | |
916 | out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status); | |
5b84dd67 | 917 | mdelay(10); |
affae2bf WD |
918 | status = (status & 0xfff5) | 0xa; |
919 | out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status); | |
920 | len=0; | |
921 | break; | |
922 | case (RH_PORT_POWER): | |
923 | len=0; /* port power ** */ | |
924 | break; | |
925 | case (RH_PORT_ENABLE): | |
926 | status = in16r(usb_base_addr+USBPORTSC1+2*(wIndex-1)); | |
927 | status = (status & 0xfff5) | USBPORTSC_PE; | |
928 | out16r(usb_base_addr+USBPORTSC1+2*(wIndex-1),status); | |
929 | len=0; | |
930 | break; | |
931 | } | |
932 | break; | |
933 | ||
934 | case RH_SET_ADDRESS: | |
935 | rh.devnum = wValue; | |
936 | len=0; | |
937 | break; | |
938 | case RH_GET_DESCRIPTOR: | |
939 | switch ((wValue & 0xff00) >> 8) { | |
940 | case (0x01): /* device descriptor */ | |
941 | i=sizeof(root_hub_config_des); | |
942 | status=i > wLength ? wLength : i; | |
943 | len = leni > status ? status : leni; | |
944 | memcpy (data, root_hub_dev_des, len); | |
945 | break; | |
946 | case (0x02): /* configuration descriptor */ | |
947 | i=sizeof(root_hub_config_des); | |
948 | status=i > wLength ? wLength : i; | |
949 | len = leni > status ? status : leni; | |
950 | memcpy (data, root_hub_config_des, len); | |
951 | break; | |
952 | case (0x03): /*string descriptors */ | |
953 | if(wValue==0x0300) { | |
954 | i=sizeof(root_hub_str_index0); | |
955 | status = i > wLength ? wLength : i; | |
956 | len = leni > status ? status : leni; | |
957 | memcpy (data, root_hub_str_index0, len); | |
958 | break; | |
959 | } | |
960 | if(wValue==0x0301) { | |
961 | i=sizeof(root_hub_str_index1); | |
962 | status = i > wLength ? wLength : i; | |
963 | len = leni > status ? status : leni; | |
964 | memcpy (data, root_hub_str_index1, len); | |
965 | break; | |
966 | } | |
967 | stat = USB_ST_STALLED; | |
968 | } | |
969 | break; | |
970 | ||
971 | case RH_GET_DESCRIPTOR | RH_CLASS: | |
972 | root_hub_hub_des[2] = 2; | |
973 | i=sizeof(root_hub_hub_des); | |
974 | status= i > wLength ? wLength : i; | |
975 | len = leni > status ? status : leni; | |
976 | memcpy (data, root_hub_hub_des, len); | |
977 | break; | |
978 | case RH_GET_CONFIGURATION: | |
979 | *(unsigned char *) data = 0x01; | |
980 | len = 1; | |
981 | break; | |
982 | case RH_SET_CONFIGURATION: | |
983 | len=0; | |
984 | break; | |
985 | default: | |
986 | stat = USB_ST_STALLED; | |
987 | } | |
988 | USB_RH_PRINTF("Root-Hub stat %lx port1: %x port2: %x\n\n",stat, | |
989 | in16r(usb_base_addr + USBPORTSC1), in16r(usb_base_addr + USBPORTSC2)); | |
990 | dev->act_len=len; | |
991 | dev->status=stat; | |
992 | return stat; | |
993 | ||
994 | } | |
995 | ||
996 | /******************************************************************************** | |
997 | * Some Debug Routines | |
998 | */ | |
999 | ||
1000 | #ifdef USB_RH_DEBUG | |
1001 | ||
1002 | static void usb_display_Req(unsigned short req) | |
1003 | { | |
1004 | USB_RH_PRINTF("- Root-Hub Request: "); | |
1005 | switch (req) { | |
1006 | case RH_GET_STATUS: | |
1007 | USB_RH_PRINTF("Get Status "); | |
1008 | break; | |
1009 | case RH_GET_STATUS | RH_INTERFACE: | |
1010 | USB_RH_PRINTF("Get Status Interface "); | |
1011 | break; | |
1012 | case RH_GET_STATUS | RH_ENDPOINT: | |
1013 | USB_RH_PRINTF("Get Status Endpoint "); | |
1014 | break; | |
1015 | case RH_GET_STATUS | RH_CLASS: | |
1016 | USB_RH_PRINTF("Get Status Class"); | |
1017 | break; /* hub power ** */ | |
1018 | case RH_GET_STATUS | RH_OTHER | RH_CLASS: | |
1019 | USB_RH_PRINTF("Get Status Class Others"); | |
1020 | break; | |
1021 | case RH_CLEAR_FEATURE | RH_ENDPOINT: | |
1022 | USB_RH_PRINTF("Clear Feature Endpoint "); | |
1023 | break; | |
1024 | case RH_CLEAR_FEATURE | RH_CLASS: | |
1025 | USB_RH_PRINTF("Clear Feature Class "); | |
1026 | break; | |
1027 | case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: | |
1028 | USB_RH_PRINTF("Clear Feature Other Class "); | |
1029 | break; | |
1030 | case RH_SET_FEATURE | RH_OTHER | RH_CLASS: | |
1031 | USB_RH_PRINTF("Set Feature Other Class "); | |
1032 | break; | |
1033 | case RH_SET_ADDRESS: | |
1034 | USB_RH_PRINTF("Set Address "); | |
1035 | break; | |
1036 | case RH_GET_DESCRIPTOR: | |
1037 | USB_RH_PRINTF("Get Descriptor "); | |
1038 | break; | |
1039 | case RH_GET_DESCRIPTOR | RH_CLASS: | |
1040 | USB_RH_PRINTF("Get Descriptor Class "); | |
1041 | break; | |
1042 | case RH_GET_CONFIGURATION: | |
1043 | USB_RH_PRINTF("Get Configuration "); | |
1044 | break; | |
1045 | case RH_SET_CONFIGURATION: | |
1046 | USB_RH_PRINTF("Get Configuration "); | |
1047 | break; | |
1048 | default: | |
1049 | USB_RH_PRINTF("****UNKNOWN**** 0x%04X ",req); | |
1050 | } | |
1051 | USB_RH_PRINTF("\n"); | |
1052 | ||
1053 | } | |
1054 | ||
1055 | static void usb_display_wValue(unsigned short wValue,unsigned short wIndex) | |
1056 | { | |
1057 | switch (wValue) { | |
1058 | case (RH_PORT_ENABLE): | |
1059 | USB_RH_PRINTF("Root-Hub: Enable Port %d\n",wIndex); | |
1060 | break; | |
1061 | case (RH_PORT_SUSPEND): | |
1062 | USB_RH_PRINTF("Root-Hub: Suspend Port %d\n",wIndex); | |
1063 | break; | |
1064 | case (RH_PORT_POWER): | |
1065 | USB_RH_PRINTF("Root-Hub: Port Power %d\n",wIndex); | |
1066 | break; | |
1067 | case (RH_C_PORT_CONNECTION): | |
1068 | USB_RH_PRINTF("Root-Hub: C Port Connection Port %d\n",wIndex); | |
1069 | break; | |
1070 | case (RH_C_PORT_ENABLE): | |
1071 | USB_RH_PRINTF("Root-Hub: C Port Enable Port %d\n",wIndex); | |
1072 | break; | |
1073 | case (RH_C_PORT_SUSPEND): | |
1074 | USB_RH_PRINTF("Root-Hub: C Port Suspend Port %d\n",wIndex); | |
1075 | break; | |
1076 | case (RH_C_PORT_OVER_CURRENT): | |
1077 | USB_RH_PRINTF("Root-Hub: C Port Over Current Port %d\n",wIndex); | |
1078 | break; | |
1079 | case (RH_C_PORT_RESET): | |
1080 | USB_RH_PRINTF("Root-Hub: C Port reset Port %d\n",wIndex); | |
1081 | break; | |
1082 | default: | |
1083 | USB_RH_PRINTF("Root-Hub: unknown %x %x\n",wValue,wIndex); | |
1084 | break; | |
1085 | } | |
1086 | } | |
1087 | ||
1088 | #endif | |
1089 | ||
1090 | ||
affae2bf WD |
1091 | #ifdef USB_UHCI_DEBUG |
1092 | ||
1093 | static int usb_display_td(uhci_td_t *td) | |
1094 | { | |
1095 | unsigned long tmp; | |
1096 | int valid; | |
1097 | ||
1098 | printf("TD at %p:\n",td); | |
1099 | ||
1100 | tmp=swap_32(td->link); | |
1101 | printf("Link points to 0x%08lX, %s first, %s, %s\n",tmp&0xfffffff0, | |
1102 | ((tmp & 0x4)==0x4) ? "Depth" : "Breath", | |
1103 | ((tmp & 0x2)==0x2) ? "QH" : "TD", | |
1104 | ((tmp & 0x1)==0x1) ? "invalid" : "valid"); | |
1105 | valid=((tmp & 0x1)==0x0); | |
1106 | tmp=swap_32(td->status); | |
1107 | printf(" %s %ld Errors %s %s %s \n %s %s %s %s %s %s\n Len 0x%lX\n", | |
1108 | (((tmp>>29)&0x1)==0x1) ? "SPD Enable" : "SPD Disable", | |
1109 | ((tmp>>28)&0x3), | |
1110 | (((tmp>>26)&0x1)==0x1) ? "Low Speed" : "Full Speed", | |
1111 | (((tmp>>25)&0x1)==0x1) ? "ISO " : "", | |
1112 | (((tmp>>24)&0x1)==0x1) ? "IOC " : "", | |
1113 | (((tmp>>23)&0x1)==0x1) ? "Active " : "Inactive ", | |
1114 | (((tmp>>22)&0x1)==0x1) ? "Stalled" : "", | |
1115 | (((tmp>>21)&0x1)==0x1) ? "Data Buffer Error" : "", | |
1116 | (((tmp>>20)&0x1)==0x1) ? "Babble" : "", | |
1117 | (((tmp>>19)&0x1)==0x1) ? "NAK" : "", | |
1118 | (((tmp>>18)&0x1)==0x1) ? "Bitstuff Error" : "", | |
1119 | (tmp&0x7ff)); | |
1120 | tmp=swap_32(td->info); | |
1121 | printf(" MaxLen 0x%lX\n",((tmp>>21)&0x7FF)); | |
1122 | printf(" %s Endpoint 0x%lX Dev Addr 0x%lX PID 0x%lX\n",((tmp>>19)&0x1)==0x1 ? "TOGGLE" : "", | |
1123 | ((tmp>>15)&0xF),((tmp>>8)&0x7F),tmp&0xFF); | |
1124 | tmp=swap_32(td->buffer); | |
1125 | printf(" Buffer 0x%08lX\n",tmp); | |
1126 | printf(" DEV %08lX\n",td->dev_ptr); | |
1127 | return valid; | |
1128 | } | |
1129 | ||
1130 | ||
1131 | void usb_show_td(int max) | |
1132 | { | |
1133 | int i; | |
1134 | if(max>0) { | |
1135 | for(i=0;i<max;i++) { | |
1136 | usb_display_td(&tmp_td[i]); | |
1137 | } | |
1138 | } | |
1139 | else { | |
1140 | i=0; | |
1141 | do { | |
1142 | printf("tmp_td[%d]\n",i); | |
1143 | }while(usb_display_td(&tmp_td[i++])); | |
1144 | } | |
1145 | } | |
1146 | ||
1147 | ||
1148 | #endif | |
1149 | #endif /* CONFIG_USB_UHCI */ | |
1150 | ||
1151 | /* EOF */ |