1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  USB Hub and device discovery code	File: usbhub.c
5    *
6    *  This module deals with hubs and device discovery.
7    *
8    *  Author:  Mitch Lichtenberg
9    *
10    *********************************************************************
11    *
12    *  Copyright 2000,2001,2002,2003,2005
13    *  Broadcom Corporation. All rights reserved.
14    *
15    *  This software is furnished under license and may be used and
16    *  copied only in accordance with the following terms and
17    *  conditions.  Subject to these conditions, you may download,
18    *  copy, install, use, modify and distribute modified or unmodified
19    *  copies of this software in source and/or binary form.  No title
20    *  or ownership is transferred hereby.
21    *
22    *  1) Any source code used, modified or distributed must reproduce
23    *     and retain this copyright notice and list of conditions
24    *     as they appear in the source file.
25    *
26    *  2) No right is granted to use any trade name, trademark, or
27    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
28    *     name may not be used to endorse or promote products derived
29    *     from this software without the prior written permission of
30    *     Broadcom Corporation.
31    *
32    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
35    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
36    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
37    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
42    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
43    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
44    *     THE POSSIBILITY OF SUCH DAMAGE.
45    ********************************************************************* */
46
47
48#ifndef _CFE_
49#include <stdio.h>
50#include <time.h>
51#include <memory.h>
52#include <stdint.h>
53#include "usbhack.h"
54#include "lib_malloc.h"
55#include "lib_queue.h"
56#else
57#include "cfe.h"
58#endif
59
60#include "usbchap9.h"
61#include "usbd.h"
62
63/* For systems with non-coherent DMA, allocate all buffers to be
64   cache-aligned and multiples of a cache line in size, so that they
65   can be safely flushed or invalidated. */
66
67#define CACHE_ALIGN    32       /* XXX place holder, big enough to now. */
68#define BUFF_ALIGN     16
69#define ALIGN(n,align) (((n)+((align)-1)) & ~((align)-1))
70
71#define usb_dma_alloc(n) (KMALLOC(ALIGN((n),CACHE_ALIGN),BUFF_ALIGN))
72#define usb_dma_free(p)  (KFREE(p))
73
74/*  *********************************************************************
75    *  Macros for common hub requests
76    ********************************************************************* */
77
78#define usbhub_set_port_feature(dev,port,feature) \
79        usb_simple_request(dev,0x23,USB_HUBREQ_SET_FEATURE,feature,port)
80
81#define usbhub_set_hub_feature(dev,feature) \
82        usb_simple_request(dev,0x20,USB_HUBREQ_SET_FEATURE,feature,0)
83
84#define usbhub_clear_port_feature(dev,port,feature) \
85        usb_simple_request(dev,0x23,USB_HUBREQ_CLEAR_FEATURE,feature,port)
86
87#define usbhub_clear_hub_feature(dev,feature) \
88        usb_simple_request(dev,0x20,USB_HUBREQ_CLEAR_FEATURE,feature,0)
89
90
91/*  *********************************************************************
92    *  Externs
93    ********************************************************************* */
94
95extern int usb_noisy;
96
97/*  *********************************************************************
98    *  Forward declarations
99    ********************************************************************* */
100
101static int usbhub_attach(usbdev_t *dev,usb_driver_t *drv);
102static int usbhub_detach(usbdev_t *dev);
103static void usbhub_markdetached(usbdev_t *dev);
104
105/*  *********************************************************************
106    *  Hub-specific data structures
107    ********************************************************************* */
108
109#define UHUB_MAX_DEVICES	8
110
111#define UHUB_FLG_NEEDSCAN	1
112
113typedef struct usbhub_softc_s {
114    usb_hub_descr_t uhub_descr;
115    usb_hub_status_t uhub_status;
116    int uhub_ipipe;
117    int uhub_ipipemps;
118    int uhub_nports;
119    unsigned int uhub_flags;
120    uint8_t *uhub_imsg;
121    usbdev_t *uhub_devices[UHUB_MAX_DEVICES];
122} usbhub_softc_t;
123
124usb_driver_t usbhub_driver = {
125    "USB Hub",
126    usbhub_attach,
127    usbhub_detach
128};
129
130usb_driver_t usbroothub_driver = {
131    "Root Hub",
132    usbhub_attach,
133    usbhub_detach
134};
135
136
137/*  *********************************************************************
138    *  usbhub_ireq_callback(ur)
139    *
140    *  this routine is called when the transfer we queued to the
141    *  interrupt endpoint on the hub completes.  It means that
142    *  *some* port on the hub needs attention.  The data indicates
143    *  which port, but for our purposes we don't really care - if
144    *  we get this callback, we'll set a flag and re-probe the bus.
145    *
146    *  Input parameters:
147    *  	   ur - usbreq that completed
148    *
149    *  Return value:
150    *  	   0
151    ********************************************************************* */
152
153static int usbhub_ireq_callback(usbreq_t *ur)
154{
155    int idx;
156    usbhub_softc_t *uhub = (ur->ur_dev->ud_private);
157
158    /*
159     * Check to see if the request was cancelled by someone
160     * deleting our endpoint.  We also check for "device not responding"
161     * which typically happens when a device is removed.
162     *
163     * XXX this is not correct, it appears that hubs sometimes do
164     * return this error.  We'll need to redo the whole way
165     * surprise detach works eventually...
166     */
167
168    if ((ur->ur_status == UR_ERR_CANCELLED) ||
169	(ur->ur_status == UR_ERR_DEVICENOTRESPONDING)) {
170	usb_free_request(ur);
171	return 0;
172	}
173
174    /*
175     * Check to see if any of our ports need attention
176     */
177
178    for (idx = 1; idx <= uhub->uhub_nports; idx++) {
179	if (ur->ur_buffer[0] & (1<<idx)) {
180
181	    /*
182	     * Mark the hub as needing a scan, and mark the bus as well
183	     * so the top-level polling will notice.
184	     */
185
186	    uhub->uhub_flags |= UHUB_FLG_NEEDSCAN;
187	    ur->ur_dev->ud_bus->ub_flags |= UB_FLG_NEEDSCAN;
188	    }
189	}
190
191
192    /*
193     * Do NOT requeue the request here.  We will do this
194     * during exploration.
195     */
196
197    usb_free_request(ur);
198
199    return 0;
200}
201
202
203/*  *********************************************************************
204    *  usbhub_get_hub_descriptor(dev,dscr,idx,maxlen)
205    *
206    *  Obtain the hub descriptor (special for hubs) from the
207    *  device.
208    *
209    *  Input parameters:
210    *  	   dev - usb device
211    *  	   dscr - place to put hub descriptor
212    *  	   idx - which hub descriptor to get (usually zero)
213    *  	   maxlen - max # of bytes to return
214    *
215    *  Return value:
216    *  	   result status
217    ********************************************************************* */
218
219static int usbhub_get_hub_descriptor(usbdev_t *dev,usb_hub_descr_t *dscr,int idx,int maxlen)
220{
221    int res;
222    uint8_t *respbuf;
223    int len;
224
225    /*
226     * Get the hub descriptor.  Get the first 8 bytes first, then get
227     * the rest if there is more.
228     */
229
230    respbuf = usb_dma_alloc(USB_HUB_DESCR_SIZE);
231    res = usb_std_request(dev,0xA0,
232			  USB_HUBREQ_GET_DESCRIPTOR,
233			  0, 0,
234			  respbuf,
235			  USB_HUB_DESCR_SIZE);
236    len = ((usb_hub_descr_t *)respbuf)->bDescriptorLength;
237    if (len > USB_HUB_DESCR_SIZE) {
238	usb_dma_free(respbuf);
239	respbuf = usb_dma_alloc(USB_HUB_DESCR_SIZE);
240	res = usb_std_request(dev,0xA0,
241			      USB_HUBREQ_GET_DESCRIPTOR,
242			      0, 0,
243			      respbuf,
244			      len);
245	}
246    memcpy(dscr, respbuf, (len <= maxlen ? len : maxlen));
247    usb_dma_free(respbuf);
248    return res;
249}
250
251
252/*  *********************************************************************
253    *  usbhub_get_hub_status(dev,status)
254    *
255    *  Obtain the hub status (special for hubs) from the
256    *  device.
257    *
258    *  Input parameters:
259    *  	   dev - usb device
260    *  	   status - where to put hub status structure
261    *
262    *  Return value:
263    *  	   # of bytes returned
264    ********************************************************************* */
265
266#if 0
267static int usbhub_get_hub_status(usbdev_t *dev,usb_hub_status_t *status)
268{
269    return usb_std_request(dev,
270			   0xA0,
271			   0x00,
272			   0,
273			   0,
274			   (uint8_t *) status,
275			   sizeof(usbhub_status_t));
276}
277#endif
278
279
280/*  *********************************************************************
281    *  usbhub_get_port_status(dev,port,status)
282    *
283    *  Obtain the port status for a particular port from
284    *  device.
285    *
286    *  Input parameters:
287    *  	   dev - usb device
288    *      port - 1-based port number
289    *  	   status - where to put port status structure
290    *
291    *  Return value:
292    *  	   # of bytes returned
293    ********************************************************************* */
294
295static int usbhub_get_port_status(usbdev_t *dev,int port,usb_port_status_t *status)
296{
297    return usb_std_request(dev,
298			   0xA3,
299			   0,
300			   0,
301			   port,
302			   (uint8_t *) status,
303			   sizeof(usb_port_status_t));
304}
305
306
307/*  *********************************************************************
308    *  usbhub_queue_intreq(dev,softc)
309    *
310    *  Queue the transfer to the interrupt pipe that will catch
311    *  the hub's port status changes
312    *
313    *  Input parameters:
314    *  	   dev - usb device
315    *  	   softc - hub-specific data
316    *
317    *  Return value:
318    *  	   nothing
319    ********************************************************************* */
320
321static void usbhub_queue_intreq(usbdev_t *dev,usbhub_softc_t *softc)
322{
323    usbreq_t *ur;
324
325    ur = usb_make_request(dev,
326			  softc->uhub_ipipe,
327			  softc->uhub_imsg,softc->uhub_ipipemps,
328			  UR_FLAG_IN | UR_FLAG_SHORTOK);
329
330    ur->ur_callback = usbhub_ireq_callback;
331
332    usb_queue_request(ur);
333}
334
335
336/*  *********************************************************************
337    *  usbhub_attach(dev,drv)
338    *
339    *  This routine is called when the hub attaches to the system.
340    *  We complete initialization for the hub and set things up so
341    *  that an explore will happen soon.
342    *
343    *  Input parameters:
344    *  	   dev - usb device
345    *  	   drv - driver structure
346    *
347    *  Return value:
348    *  	   0
349    ********************************************************************* */
350
351static int usbhub_attach(usbdev_t *dev,usb_driver_t *drv)
352{
353    usb_device_status_t devstatus;
354    usb_config_descr_t *cfgdscr;
355    usb_interface_descr_t *ifdscr;
356    usb_endpoint_descr_t *epdscr;
357    usbhub_softc_t *softc;
358
359    /*
360     * Remember the driver dispatch.
361     */
362
363    dev->ud_drv = drv;
364
365    softc = KMALLOC(sizeof(usbhub_softc_t),0);
366    memset(softc,0,sizeof(usbhub_softc_t));
367    softc->uhub_imsg = NULL;
368    dev->ud_private = softc;
369
370    /*
371     * Dig out the data from the configuration descriptor
372     * (we got this from the device before attach time)
373     */
374
375    cfgdscr = dev->ud_cfgdescr;
376    epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,0);
377    ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0);
378
379    /*
380     * Get device status (is this really necessary?)
381     */
382
383    usb_get_device_status(dev,&devstatus);
384
385    /*
386     * Set us to configuration index 0
387     */
388
389    usb_set_configuration(dev,cfgdscr->bConfigurationValue);
390
391    /*
392     * Get the hub descriptor.
393     */
394
395    usbhub_get_hub_descriptor(dev,&softc->uhub_descr,0,sizeof(usb_hub_descr_t));
396
397    /*
398     * remember stuff from the hub descriptor
399     */
400
401    softc->uhub_nports = softc->uhub_descr.bNumberOfPorts;
402
403    /*
404     * Open the interrupt pipe
405     */
406
407    softc->uhub_ipipemps = GETUSBFIELD(epdscr,wMaxPacketSize);
408    softc->uhub_imsg = usb_dma_alloc(softc->uhub_ipipemps);
409    softc->uhub_ipipe = usb_open_pipe(dev,epdscr);
410
411    /*
412     * Mark the bus and the hub as needing service.
413     */
414
415    softc->uhub_flags |= UHUB_FLG_NEEDSCAN;
416    dev->ud_bus->ub_flags |= UB_FLG_NEEDSCAN;
417
418    /*
419     * Okay, that's it.  The top-level USB daemon will notice
420     * that the bus needs service and will invoke the exploration code.
421     * This may in turn require additional explores until
422     * everything settles down.
423     */
424
425    return 0;
426}
427
428
429/*  *********************************************************************
430    *  usbhub_detach(dev)
431    *
432    *  Called when a hub is removed from the system - we remove
433    *  all subordinate devices.
434    *
435    *  Input parameters:
436    *  	   dev - device (hub) that was removed
437    *
438    *  Return value:
439    *  	   0
440    ********************************************************************* */
441
442static int usbhub_detach(usbdev_t *dev)
443{
444    usbhub_softc_t *hub;
445    usbdev_t *deldev;
446    int idx;
447
448    if (!IS_HUB(dev)) return 0;		/* should not happen */
449
450    hub = dev->ud_private;
451    for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) {
452	deldev = hub->uhub_devices[idx];
453	if (deldev) {
454	    if (usb_noisy > 0)
455		console_log("USB: Removing device attached to bus %d hub %d port %d",
456			    dev->ud_bus->ub_num,
457			    dev->ud_address,idx+1);
458	    if (deldev->ud_drv) {
459		/* close open pipes, cancel reqs */
460		usb_destroy_all_pipes(deldev);
461		/*
462		 * Try to process the done queue.  This will complete any
463		 * requests that made it out of the pipes while we were
464		 * doing the stuff above.
465		 */
466		usb_poll(deldev->ud_bus);
467		/* Call detach method, clean up device softc */
468		(*(deldev->ud_drv->udrv_detach))(deldev);
469		}
470	    else {
471		if (usb_noisy > 0) {
472		    console_log("USB: Detached device on bus %d hub %d port %d "
473			   "has no methods",
474			   dev->ud_bus->ub_num,
475			   dev->ud_address,idx+1);
476		    }
477		}
478	    if (deldev->ud_cfgdescr) usb_dma_free(deldev->ud_cfgdescr);
479	    usb_destroy_device(deldev);
480	    }
481	}
482
483    if (hub->uhub_imsg != NULL) {
484	usb_dma_free(hub->uhub_imsg);
485	}
486    KFREE(hub);				/* remove softc */
487
488    return 0;
489}
490
491
492
493/*  *********************************************************************
494    *  usbhub_map_tree1(dev,level,func,arg)
495    *
496    *  This routine is used in recursive device tree exploration.
497    *  We call 'func' for each device at this tree, and descend
498    *  when we run into hubs
499    *
500    *  Input parameters:
501    *  	   dev - current device pointer
502    *  	   level - current nesting level
503    *  	   func - function to call
504    *  	   arg - argument to pass to function
505    *
506    *  Return value:
507    *  	   nothing
508    ********************************************************************* */
509
510static void usbhub_map_tree1(usbdev_t *dev,int level,
511			     int (*func)(usbdev_t *dev,void *arg),void *arg)
512{
513    usbhub_softc_t *hub;
514    int idx;
515
516    (*func)(dev,arg);
517
518    if (IS_HUB(dev)) {
519	hub = dev->ud_private;
520	for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) {
521	    if (hub->uhub_devices[idx]) {
522		usbhub_map_tree1(hub->uhub_devices[idx],level+1,func,arg);
523		}
524	    }
525	}
526}
527
528/*  *********************************************************************
529    *  usbhub_map_tree(bus,func,arg)
530    *
531    *  Call a function for each device in the tree
532    *
533    *  Input parameters:
534    *  	   bus - bus to scan
535    *  	   func - function to call
536    *  	   arg - argument to pass to function
537    *
538    *  Return value:
539    *  	   nothing
540    ********************************************************************* */
541
542void usbhub_map_tree(usbbus_t *bus,int (*func)(usbdev_t *dev,void *arg),void *arg)
543{
544    usbhub_map_tree1(bus->ub_roothub,0,func,arg);
545}
546
547void usbhub_map_from_device(usbdev_t *dev,int (*func)(usbdev_t *dev,void *arg),void *arg)
548{
549    usbhub_map_tree1(dev,0,func,arg);
550}
551
552
553/*  *********************************************************************
554    *  usbhub_dumpbus1(dev,arg)
555    *
556    *  map function to dump devices in the device tree
557    *
558    *  Input parameters:
559    *  	   dev - device we're working on
560    *  	   arg - argument from map_tree call
561    *
562    *  Return value:
563    *  	   0
564    ********************************************************************* */
565
566static int usbhub_dumpbus1(usbdev_t *dev,void *arg)
567{
568    uint32_t *verbose = (uint32_t *) arg;
569
570    if ((*verbose & 0x00FF) && (dev->ud_address != (*verbose & 0x00FF))) return 0;
571
572    if (*verbose & 0x100) {
573	printf("============================================================================\n");
574	}
575
576    usb_dbg_showdevice(dev);
577
578    if (*verbose & 0x100) {
579	usb_dbg_dumpdescriptors(dev,(uint8_t *) &(dev->ud_devdescr),dev->ud_devdescr.bLength);
580	usb_dbg_dumpcfgdescr(dev,0);
581	}
582
583    return 0;
584}
585
586
587/*  *********************************************************************
588    *  usbhub_dumpbus(bus,verbose)
589    *
590    *  Dump information about devices on the USB bus.
591    *
592    *  Input parameters:
593    *  	   bus - bus to dump
594    *  	   verbose - nonzero to display more info, like descriptors
595    *
596    *  Return value:
597    *  	   nothing
598    ********************************************************************* */
599
600void usbhub_dumpbus(usbbus_t *bus,uint32_t verbose)
601{
602    usbhub_map_tree(bus,usbhub_dumpbus1,&verbose);
603}
604
605
606
607/*  *********************************************************************
608    *  usbhub_reset_devicee(dev,port,status)
609    *
610    *  Reset a device on a hub port.  This routine does a
611    *  USB_PORT_FEATURE_RESET on the specified port, waits for the
612    *  bit to clear, and returns.  It is used to get a device into the
613    *  DEFAULT state according to the spec.
614    *
615    *  Input parameters:
616    *  	   dev - hub device
617    *  	   port - port number(1-based)
618    *  	   status - place to return port_status structure after
619    *  	           reset completes
620    *
621    *  Return value:
622    *  	   nothing
623    ********************************************************************* */
624
625static void usbhub_reset_device(usbdev_t *dev,int port,usb_port_status_t *portstatus)
626{
627    if (usb_noisy > 0)
628	console_log("USB: Resetting device on bus %d port %d",dev->ud_bus->ub_num,port);
629#ifndef _CFE_
630    fflush(stdout);
631#endif
632
633    usbhub_set_port_feature(dev,port,USB_PORT_FEATURE_RESET);
634
635    usbhub_get_port_status(dev,port,portstatus);
636
637    for (;;) {
638	usbhub_get_port_status(dev,port,portstatus);
639	if ((GETUSBFIELD((portstatus),wPortStatus) & USB_PORT_STATUS_RESET) == 0) break;
640	usb_delay_ms(dev->ud_bus,250);
641	}
642    usb_delay_ms(dev->ud_bus,250);
643
644    usbhub_clear_port_feature(dev,port,USB_PORT_FEATURE_C_PORT_RESET);
645}
646
647
648
649/*  *********************************************************************
650    *  usbhub_scan_ports(dev,arg)
651    *
652    *  Scan the ports on this hub for new or removed devices.
653    *
654    *  Input parameters:
655    *  	   dev - hub device
656    *  	   arg - passed from bus scan main routines
657    *
658    *  Return value:
659    *  	   nothing
660    ********************************************************************* */
661
662static void usbhub_scan_ports(usbdev_t *dev,void *arg)
663{
664    uint16_t current;
665    uint16_t changed;
666    usbhub_softc_t *softc;
667    int idx;
668    int res;
669    int len;
670    uint8_t *buf;
671    usbdev_t *newdev;
672    usb_driver_t *newdrv;
673    int addr;
674    usb_port_status_t *portstatus;
675    usb_config_descr_t cfgdescr;
676    unsigned int powerondelay;
677
678    if (!IS_HUB(dev)) return;		/* should not happen.  */
679
680    portstatus = usb_dma_alloc(sizeof(usb_port_status_t));
681    if (portstatus == NULL) return;
682
683    /*
684     * We know this is a hub.  Get the softc back.
685     */
686
687    softc = (usbhub_softc_t *) dev->ud_private;
688
689    powerondelay = ((unsigned int) softc->uhub_descr.bPowerOnToPowerGood)*2 + 20;
690
691    /*
692     * Turn on the power to the ports whose power is not yet on.
693     */
694
695    for (idx = 0; idx < softc->uhub_nports; idx++) {
696
697	usbhub_get_port_status(dev,idx+1,portstatus);
698
699	current = GETUSBFIELD(portstatus,wPortStatus);
700	changed = GETUSBFIELD(portstatus,wPortChange);
701	if (usb_noisy > 1) {
702	    printf("BeforePowerup: port %d status %04X changed %04X\n",idx+1,current,changed);
703	    }
704
705	if (!(current & USB_PORT_STATUS_POWER)) {
706	    if (usb_noisy > 1) console_log("USB: Powering up bus %d port %d",
707				      dev->ud_bus->ub_num,idx+1);
708	    usbhub_set_port_feature(dev,idx+1,USB_PORT_FEATURE_POWER);
709	    usb_delay_ms(dev->ud_bus,powerondelay);
710	    }
711	}
712
713    /*
714     * Begin exploration at this level.
715     */
716
717    for (idx = 0; idx < softc->uhub_nports; idx++) {
718
719	usbhub_get_port_status(dev,idx+1,portstatus);
720
721	current = GETUSBFIELD(portstatus,wPortStatus);
722	changed = GETUSBFIELD(portstatus,wPortChange);
723
724	if (usb_noisy > 0) {
725	    printf("USB: Explore: Bus %d Hub %d port %d status %04X changed %04X\n",
726		   dev->ud_bus->ub_num,
727		   dev->ud_address,idx+1,current,changed);
728	    usb_dbg_dumpportstatus(idx+1,portstatus,1);
729	    }
730
731
732//	if (changed & USB_PORT_STATUS_RESET) {
733//	    usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_RESET);
734//	    }
735
736	if (changed & USB_PORT_STATUS_ENABLED) {
737	    usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_ENABLE);
738	    }
739
740	if (changed & USB_PORT_STATUS_CONNECT) {
741	    /*
742	     * A device was either connected or disconnected.
743	     * Clear the status change first.
744	     */
745
746	    usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_CONNECTION);
747
748	    if (current & USB_PORT_STATUS_CONNECT) {
749
750		/*
751		 * The device has been CONNECTED.
752		 */
753
754		console_log("USB: New device connected to bus %d hub %d port %d",
755			    dev->ud_bus->ub_num,
756			    dev->ud_address,idx+1);
757
758		/*
759		 * Reset the device.  Reuse our old port status structure
760		 * so we get the latest status.  Some devices do not report
761		 * lowspeed until they are reset.
762		 */
763
764		usbhub_reset_device(dev,idx+1,portstatus);
765		current = GETUSBFIELD(portstatus,wPortStatus);
766		changed = GETUSBFIELD(portstatus,wPortChange);
767
768		/*
769		 * Create a device for this port.
770		 */
771
772		newdev = usb_create_device(dev->ud_bus,(current & USB_PORT_STATUS_LOWSPD) ? 1 : 0);
773
774		/*
775		 * Get the device descriptor.
776		 */
777
778		res = usb_get_device_descriptor(newdev,&newdev->ud_devdescr,TRUE);
779
780		if (usb_noisy > 1) usb_dbg_dumpdescriptors(newdev,(uint8_t *) &(newdev->ud_devdescr),8);
781
782		/*
783		 * Set up the max packet size for the control endpoint,
784		 * then get the rest of the descriptor.
785		 */
786
787		usb_set_ep0mps(newdev,newdev->ud_devdescr.bMaxPacketSize0);
788		res = usb_get_device_descriptor(newdev,&newdev->ud_devdescr,FALSE);
789
790		/*
791		 * Obtain a new address and set the address of the
792		 * root hub to this address.
793		 */
794
795		addr = usb_new_address(newdev->ud_bus);
796		res = usb_set_address(newdev,addr);
797
798		/*
799		 * Get the configuration descriptor and all the
800		 * associated interface and endpoint descriptors.
801		 */
802
803		res = usb_get_config_descriptor(newdev,&cfgdescr,0,
804						sizeof(usb_config_descr_t));
805		if (res != sizeof(usb_config_descr_t)) {
806		    printf("[a] usb_get_config_descriptor returns %d\n",res);
807		    }
808
809		len = GETUSBFIELD(&cfgdescr,wTotalLength);
810		buf = usb_dma_alloc(len);
811
812		res = usb_get_config_descriptor(newdev,(usb_config_descr_t *)buf,0,len);
813		if (res != len) {
814		    printf("[b] usb_get_config_descriptor returns %d\n",res);
815		    }
816
817		newdev->ud_cfgdescr = (usb_config_descr_t *) buf;
818
819		if (usb_noisy > 1) usb_dbg_dumpdescriptors(newdev,buf,len);
820
821		/*
822		 * Point the hub at the devices it owns
823		 */
824
825		softc->uhub_devices[idx] = newdev;
826
827		/*
828		 * Find the driver for this.  It had better be the hub
829		 * driver.
830		 */
831
832		newdrv = usb_find_driver(newdev);
833
834		/*
835		 * Call the attach method.
836		 */
837
838		if (newdrv) {
839		    newdev->ud_drv = newdrv;	/* remember driver dispatch in device */
840		    (*(newdrv->udrv_attach))(newdev,newdrv);
841		    }
842		}
843
844	    else {
845
846		/*
847		 * The device has been DISCONNECTED.
848		 */
849
850		console_log("USB: Device disconnected from bus %d hub %d port %d",
851			    dev->ud_bus->ub_num,
852			    dev->ud_address,idx+1);
853
854		/*
855		 * Recover pointer to device below hub and clear
856		 * this pointer.
857		 */
858
859		newdev = softc->uhub_devices[idx];	/* Get device pointer */
860
861		usbhub_markdetached(newdev);		/* mark device and all subordinate
862							   devices as "removing" */
863
864		softc->uhub_devices[idx] = NULL;	/* remove device from hub */
865
866		/*
867		 * Deassign the USB device's address and then
868		 * call detach method to free resources.  Devices that
869		 * do not have drivers will not have any methods.
870		 */
871
872		if (newdev) {
873		    if (newdev->ud_drv) {
874			/* close open pipes, cancel reqs */
875			usb_destroy_all_pipes(newdev);
876			/*
877			 * Try to process the done queue.  This will complete any
878			 * requests that made it out of the pipes while we were
879			 * doing the stuff above.
880			 */
881			usb_poll(newdev->ud_bus);
882			/* Call detach method, clean up device softc */
883			(*(newdev->ud_drv->udrv_detach))(newdev);
884			}
885		    else {
886			if (usb_noisy > 0) {
887			    console_log("USB: Detached device on bus %d hub %d port %d "
888				   "has no methods",
889				   dev->ud_bus->ub_num,
890				   dev->ud_address,idx+1);
891			    }
892			}
893
894		    if (newdev->ud_cfgdescr) usb_dma_free(newdev->ud_cfgdescr);
895
896		    usb_destroy_device(newdev);
897		    }
898
899		}
900	    }
901
902	}
903
904    usb_dma_free(portstatus);
905
906    /*
907     * Queue up a request for the interrupt pipe.  This will catch further
908     * changes at this port.
909     */
910
911    usbhub_queue_intreq(dev,softc);
912
913}
914
915/*  *********************************************************************
916    *  usbhub_markdetached(dev)
917    *
918    *  Mark a device and all devices below it as "removing" so we
919    *  will change the status of pending requests to cancelled.
920    *
921    *  Input parameters:
922    *  	   dev - device in the tree to start at
923    *
924    *  Return value:
925    *  	   nothing
926    ********************************************************************* */
927
928static int usbhub_markdetached1(usbdev_t *dev,void *arg)
929{
930    dev->ud_flags |= UD_FLAG_REMOVING;
931    return 0;
932}
933
934static void usbhub_markdetached(usbdev_t *dev)
935{
936    usbhub_map_from_device(dev,usbhub_markdetached1,NULL);
937}
938
939/*  *********************************************************************
940    *  usbhub_scan1(dev,arg)
941    *
942    *  Scan one device at this level, or descend if we run into a hub
943    *  This is part of the device discovery code.
944    *
945    *  Input parameters:
946    *  	   dev - current device, maybe a hub
947    *  	   arg - passed from main scan routine
948    *
949    *  Return value:
950    *  	   0
951    ********************************************************************* */
952
953
954static int usbhub_scan1(usbdev_t *dev,void *arg)
955{
956    usbhub_softc_t *hub;
957
958    /*
959     * If the device is not a hub, we've reached the leaves of the
960     * tree.
961     */
962
963    if (!IS_HUB(dev)) return 0;
964
965    /*
966     * Otherwise, scan the ports on this hub.
967     */
968
969    hub = dev->ud_private;
970
971    if (hub->uhub_flags & UHUB_FLG_NEEDSCAN) {
972	hub->uhub_flags &= ~UHUB_FLG_NEEDSCAN;
973	usbhub_scan_ports(dev,arg);
974	}
975
976    return 0;
977}
978
979/*  *********************************************************************
980    *  usb_scan(bus)
981    *
982    *  Scan the bus looking for new or removed devices
983    *
984    *  Input parameters:
985    *  	   bus - bus to scan
986    *
987    *  Return value:
988    *  	   nothing
989    ********************************************************************* */
990
991void usb_scan(usbbus_t *bus)
992{
993    /*
994     * Call our tree walker with the scan function.
995     */
996
997    usbhub_map_tree(bus,usbhub_scan1,NULL);
998}
999
1000
1001
1002