Exemplo n.º 1
0
char *
usbd_devinfo_alloc(struct usbd_device *dev, int showclass)
{
	char *devinfop;

	devinfop = kmem_alloc(DEVINFOSIZE, KM_SLEEP);
	usbd_devinfo(dev, showclass, devinfop, DEVINFOSIZE);
	return devinfop;
}
Exemplo n.º 2
0
static int
atausb_attach(device_t dev)
{
    struct atausb_softc *sc = device_get_softc(dev);
    struct usb_attach_arg *uaa = device_get_ivars(dev);
    usb_interface_descriptor_t *id;
    usb_endpoint_descriptor_t *ed;
    usbd_device_handle udev;
    usb_device_request_t request;
    char devinfo[1024], *proto, *subclass;
    u_int8_t maxlun;
    int err, i;

    sc->dev = dev;
    usbd_devinfo(uaa->device, 0, devinfo);
    device_set_desc_copy(dev, devinfo);
    sc->bulkin = sc->bulkout = sc->bulkirq = -1;
    sc->bulkin_pipe = sc->bulkout_pipe= sc->bulkirq_pipe = NULL;
    sc->iface = uaa->iface;
    sc->ifaceno = uaa->ifaceno;
    sc->maxlun = 0;
    sc->timeout = 5000;
    sc->locked_ch = NULL;
    sc->restart_ch = NULL;
    spin_init(&sc->locked_mtx); 

    id = usbd_get_interface_descriptor(sc->iface);
    switch (id->bInterfaceProtocol) {
    case UIPROTO_MASS_BBB:
    case UIPROTO_MASS_BBB_OLD:
	    proto = "Bulk-Only";
	    break;
    case UIPROTO_MASS_CBI:
	    proto = "CBI";
	    break;
    case UIPROTO_MASS_CBI_I:
	    proto = "CBI with CCI";
	    break;
    default:
	    proto = "Unknown";
    }
    switch (id->bInterfaceSubClass) {
    case UISUBCLASS_RBC:
	    subclass = "RBC";
	    break;
    case UISUBCLASS_QIC157:
    case UISUBCLASS_SFF8020I:
    case UISUBCLASS_SFF8070I:
	    subclass = "ATAPI";
	    break;
    case UISUBCLASS_SCSI:
	    subclass = "SCSI";
	    break;
    case UISUBCLASS_UFI:
	    subclass = "UFI";
	    break;
    default:
	    subclass = "Unknown";
    }
    device_printf(dev, "using %s over %s\n", subclass, proto);
    if (strcmp(proto, "Bulk-Only") ||
	(strcmp(subclass, "ATAPI") && strcmp(subclass, "SCSI")))
	return ENXIO;

    for (i = 0 ; i < id->bNumEndpoints ; i++) {
	if (!(ed = usbd_interface2endpoint_descriptor(sc->iface, i))) {
	    device_printf(sc->dev, "could not read endpoint descriptor\n");
	    return ENXIO;
	}
	if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
	    (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
	    sc->bulkin = ed->bEndpointAddress;
	}
	if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
	           (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
	    sc->bulkout = ed->bEndpointAddress;
	}
	if (id->bInterfaceProtocol == UIPROTO_MASS_CBI_I &&
	           UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
	           (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
	    sc->bulkirq = ed->bEndpointAddress;
	}
    }

    /* check whether we found at least the endpoints we need */
    if (!sc->bulkin || !sc->bulkout) {
	device_printf(sc->dev, "needed endpoints not found (%d,%d)\n",
		      sc->bulkin, sc->bulkout);
	atausb_detach(dev);
	return ENXIO;
    }

    /* open the pipes */
    if (usbd_open_pipe(sc->iface, sc->bulkout,
		       USBD_EXCLUSIVE_USE, &sc->bulkout_pipe)) {
	device_printf(sc->dev, "cannot open bulkout pipe (%d)\n", sc->bulkout);
	atausb_detach(dev);
	return ENXIO;
    }
    if (usbd_open_pipe(sc->iface, sc->bulkin,
		       USBD_EXCLUSIVE_USE, &sc->bulkin_pipe)) {
	device_printf(sc->dev, "cannot open bulkin pipe (%d)\n", sc->bulkin);
	atausb_detach(dev);
	return ENXIO;
    }
    if (id->bInterfaceProtocol == UIPROTO_MASS_CBI_I) {
	if (usbd_open_pipe(sc->iface, sc->bulkirq,
			   USBD_EXCLUSIVE_USE, &sc->bulkirq_pipe)) {
	    device_printf(sc->dev, "cannot open bulkirq pipe (%d)\n",
	    		  sc->bulkirq);
	    atausb_detach(dev);
	    return ENXIO;
	}
    }
    sc->state = ATAUSB_S_ATTACH;

    /* alloc needed number of transfer handles */
    for (i = 0; i < ATAUSB_T_MAX; i++) {
	sc->transfer[i] = usbd_alloc_xfer(uaa->device);
	if (!sc->transfer[i]) {
	    device_printf(sc->dev, "out of memory\n");
	    atausb_detach(dev);
	    return ENXIO;
	}
    }

    /* driver is ready to process requests here */
    sc->state = ATAUSB_S_IDLE;

    /* get number of devices so we can add matching channels */
    usbd_interface2device_handle(sc->iface, &udev);
    request.bmRequestType = UT_READ_CLASS_INTERFACE;
    request.bRequest = 0xfe; /* GET_MAX_LUN; */
    USETW(request.wValue, 0);
    USETW(request.wIndex, sc->ifaceno);
    USETW(request.wLength, sizeof(maxlun));
    switch ((err = usbd_do_request(udev, &request, &maxlun))) {
    case USBD_NORMAL_COMPLETION:
	if (bootverbose)
	    device_printf(sc->dev, "maxlun=%d\n", maxlun);
	sc->maxlun = maxlun;
	break;
    default:
	if (bootverbose)
	    device_printf(sc->dev, "get maxlun not supported %s\n",
	usbd_errstr(err));
    }

    /* ata channels are children to this USB control device */
    for (i = 0; i <= sc->maxlun; i++) {
	/* XXX TGEN devclass_find_free_unit() implementation */
	int freeunit = 2;
	while (freeunit < devclass_get_maxunit(ata_devclass) &&
	       devclass_get_device(ata_devclass, freeunit) != NULL)
	    freeunit++;
	if (!device_add_child(sc->dev, "ata", freeunit)) {
	    device_printf(sc->dev, "failed to attach ata child device\n");
	    atausb_detach(dev);
	    return ENXIO;
	}
    }
    bus_generic_attach(sc->dev);
    return 0;
}
Exemplo n.º 3
0
/*
 ****************************************************************
 *	Função de "attach"					*
 ****************************************************************
 */
int
uhub_attach (struct device *dev)
{
        struct uhub_softc		*sc;
        struct usb_attach_arg		*uaa  = dev->ivars;
	struct usbd_device		*udev = uaa->device;
	struct usbd_hub			*hub  = NULL;
	struct usb_device_request	req;
	struct usb_hub_descriptor	*hubdesc = NULL;
	struct usbd_interface		*iface;
	struct usb_endpoint_descriptor	*ed;
	int				p, port, nports, nremov, pwrdly, err;

	/*
	 *	Aloca e zera a estrutura "softc"
	 */
	if ((sc = dev->softc = malloc_byte (sizeof (struct uhub_softc))) == NULL)
		return (-1);

	memclr (sc, sizeof (struct uhub_softc));

#if (0)	/*******************************************************/
{
	char				*devinfo;

	if ((devinfo = malloc_byte (1024)) == NULL)
		goto bad;

	memclr (devinfo, 1024);

	usbd_devinfo (udev, USBD_SHOW_INTERFACE_CLASS, devinfo);

	device_set_desc_copy (dev, devinfo);

	free_byte (devinfo);
}
#endif	/*******************************************************/

	sc->sc_hub = udev;
	sc->sc_dev = dev;

	if (err = usbd_set_config_index (udev, 0, 1))
	{
		printf ("uhub_attach (%s): erro na configuração (%s)\n", dev->nameunit, usbd_errstr (err));
		goto bad;
	}

	if (udev->depth > USB_HUB_MAX_DEPTH)
	{
		printf
		(	"uhub_attach (%s): profundidade máxima excedida (%d > %d), \"hub\" ignorado\n",
			dev->nameunit, udev->depth, USB_HUB_MAX_DEPTH
		);
		goto bad;
	}

	/* Get hub descriptor */

	if ((hubdesc = malloc_byte (sizeof (struct usb_hub_descriptor))) == NULL)
		{ err = USBD_NOMEM; goto bad; }

	req.bmRequestType	= UT_READ_CLASS_DEVICE;
	req.bRequest		= UR_GET_DESCRIPTOR;

	USETW2 (req.wValue, (udev->address > 1 ? UDESC_HUB : 0), 0);
	USETW  (req.wIndex, 0);
	USETW  (req.wLength, USB_HUB_DESCRIPTOR_SIZE);

	err = usbd_do_request (udev, &req, hubdesc);

	nports = hubdesc->bNbrPorts;

	if (err == 0 && nports > 7)
	{
		USETW (req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports + 1) / 8);

		err = usbd_do_request (udev, &req, hubdesc);
	}

	if (err)
	{
		printf
		(	"uhub_attach (%s): erro ao ler descritor do hub (%s)\n",
			dev->nameunit, usbd_errstr (err)
		);

		goto bad;
	}

	for (nremov = 0, port = 1; port <= nports; port++)
	{
		if (!UHD_NOT_REMOV (hubdesc, port))
			nremov++;
	}

	if (nports == 0)
		{ printf ("%s: hub sem portas ignorado\n", dev->nameunit); goto bad; }

	printf
	(	"%s: %d porta%s, %d removíve%s, %s energizadas\n",
		dev->nameunit,
		nports, nports != 1 ? "s" : "",
		nremov, nremov != 1 ? "is" : "l",
		udev->self_powered ? "auto" : "bus"
	);

	if ((hub = malloc_byte (sizeof (*hub) + (nports - 1) * sizeof (struct usbd_port))) == NULL)
		goto bad;

	memclr (hub, (sizeof (*hub) + (nports - 1) * sizeof (struct usbd_port)));

	udev->hub		= hub;
	udev->hub->hubsoftc	= sc;
	hub->explore		= uhub_explore;
	hub->hubdesc		= *hubdesc;

	free_byte (hubdesc); hubdesc = NULL;

#ifdef	USB_MSG
	printf
	(	"uhub_attach: selfpowered=%d, parent=%p, parent->selfpowered=%d\n",
		 dev->self_powered, dev->powersrc->parent,
		 dev->powersrc->parent ? dev->powersrc->parent->self_powered : 0
	);
#endif	USB_MSG

	if (!udev->self_powered && udev->powersrc->parent != NULL && !udev->powersrc->parent->self_powered)
	{
		printf
		(	"uhub_attach (%s): bus powered hub connected to bus powered hub, ignored\n",
			dev->nameunit
		);
		goto bad;
	}

	/* Set up interrupt pipe */

	if (usbd_device2interface_handle (udev, 0, &iface))
	{
		printf ("uhub_attach (%s): no interface handle\n", dev->nameunit);
		goto bad;
	}

	if ((ed = usbd_interface2endpoint_descriptor (iface, 0)) == NULL)
	{
		printf ("uhub_attach (%s): no endpoint descriptor\n", dev->nameunit);
		goto bad;
	}

	if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT)
	{
		printf ("uhub_attach (%s): bad interrupt endpoint\n", dev->nameunit);
		goto bad;
	}

	if
	(	usbd_open_pipe_intr
		(	iface, ed->bEndpointAddress,
			USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status, 
			sizeof (sc->sc_status), uhub_intr, UHUB_INTR_INTERVAL
		)
	)
	{
		printf ("uhub_attach (%s): cannot open interrupt pipe\n", dev->nameunit);
		goto bad;
	}

	/* Wait with power off for a while */

	usbd_delay_ms (udev, USB_POWER_DOWN_TIME);

	/*
	 * To have the best chance of success we do things in the exact same
	 * order as Windoze98.  This should not be necessary, but some
	 * devices do not follow the USB specs to the letter.
	 *
	 * These are the events on the bus when a hub is attached:
	 *  Get device and config descriptors (see attach code)
	 *  Get hub descriptor (see above)
	 *  For all ports
	 *     turn on power
	 *     wait for power to become stable
	 * (all below happens in explore code)
	 *  For all ports
	 *     clear C_PORT_CONNECTION
	 *  For all ports
	 *     get port status
	 *     if device connected
	 *        wait 100 ms
	 *        turn on reset
	 *        wait
	 *        clear C_PORT_RESET
	 *        get port status
	 *        proceed with device attachment
	 */

	/* Set up data structures */

	for (p = 0; p < nports; p++)
	{
		struct usbd_port	*up = &hub->ports[p];

		up->device = NULL;
		up->parent = udev;
		up->portno = p+1;

		if (udev->self_powered) /* Self powered hub, give ports maximum current */
			up->power = USB_MAX_POWER;
		else
			up->power = USB_MIN_POWER;

		up->restartcnt = 0;
	}

	/* XXX should check for none, individual, or ganged power? */

	pwrdly = udev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR + USB_EXTRA_POWER_UP_TIME;

	for (port = 1; port <= nports; port++)
	{
		/* Turn the power on */

		if (err = usbd_set_port_feature (udev, port, UHF_PORT_POWER))
		{
			printf
			(	"uhub_attach (%s): port %d power on failed, %s\n", 
				dev->nameunit, port, usbd_errstr (err)
			);
		}

#ifdef	USB_MSG
		printf ("uhub_attach: turn on port %d power\n", port);
#endif	USB_MSG

		/* Wait for stable power */

		usbd_delay_ms (udev, pwrdly);
	}

	/* The usual exploration will finish the setup */

	sc->sc_running = 1;

	return (0);

	/*
	 *	Em caso de erro, ...
	 */
    bad:
	if (hubdesc != NULL)
		free_byte (hubdesc);

	if (hub != NULL)
		free_byte (hub);

	udev->hub = NULL;

	free_byte (sc);	dev->softc = NULL;

	return (-1);

}	/* end uhub_attach */
Exemplo n.º 4
0
usbd_status
usbd_probe_and_attach(device_t parent, usbd_device_handle dev,
		      int port, int addr)
{
	struct usb_attach_arg uaa;
	usb_device_descriptor_t *dd = &dev->ddesc;
	int found, i, confi, nifaces;
	usbd_status err;
	device_t *tmpdv;
	usbd_interface_handle ifaces[256]; /* 256 is the absolute max */
	char *devinfo;

	/* XXX FreeBSD may leak resources on failure cases -- fixme */
 	device_t bdev;
	struct usb_attach_arg *uaap;

	devinfo = kmalloc(1024, M_USB, M_NOWAIT);
	if (devinfo == NULL) {
		device_printf(parent,
			      "Can't allocate memory for probe string\n");
		return (USBD_NOMEM);
	}
	bdev = device_add_child(parent, NULL, -1);
	if (!bdev) {
		kfree(devinfo, M_USB);
		device_printf(parent, "Device creation failed\n");
		return (USBD_INVAL);
	}
	uaap = kmalloc(sizeof(uaa), M_USB, M_WAITOK);
	device_set_ivars(bdev, uaap);
	uaa.device = dev;
	uaa.iface = NULL;
	uaa.ifaces = NULL;
	uaa.nifaces = 0;
	uaa.usegeneric = 0;
	uaa.port = port;
	uaa.configno = UHUB_UNK_CONFIGURATION;
	uaa.ifaceno = UHUB_UNK_INTERFACE;
	uaa.vendor = UGETW(dd->idVendor);
	uaa.product = UGETW(dd->idProduct);
	uaa.release = UGETW(dd->bcdDevice);
	uaa.matchlvl = 0;

	/* First try with device specific drivers. */
	DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n"));

	dev->ifacenums = NULL;
	dev->subdevs = kmalloc(2 * sizeof(device_t), M_USB, M_WAITOK);
	dev->subdevs[0] = bdev;
	dev->subdevs[1] = 0;
	*uaap = uaa;
	usbd_devinfo(dev, 1, devinfo);
	device_set_desc_copy(bdev, devinfo);
	if (device_probe_and_attach(bdev) == 0) {
		kfree(devinfo, M_USB);
		return (USBD_NORMAL_COMPLETION);
	}

	/*
	 * Free subdevs so we can reallocate it larger for the number of
	 * interfaces 
	 */
	tmpdv = dev->subdevs;
	dev->subdevs = NULL;
	kfree(tmpdv, M_USB);
	DPRINTF(("usbd_probe_and_attach: no device specific driver found\n"));

	DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n",
		 dd->bNumConfigurations));
	/* Next try with interface drivers. */
	for (confi = 0; confi < dd->bNumConfigurations; confi++) {
		DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n",
			    confi));
		err = usbd_set_config_index(dev, confi, 1);
		if (err) {
#ifdef USB_DEBUG
			DPRINTF(("%s: port %d, set config at addr %d failed, "
				 "error=%s\n", device_get_nameunit(parent), port,
				 addr, usbd_errstr(err)));
#else
			kprintf("%s: port %d, set config at addr %d failed\n",
			       device_get_nameunit(parent), port, addr);
#endif
			kfree(devinfo, M_USB);
 			return (err);
		}
		nifaces = dev->cdesc->bNumInterface;
		uaa.configno = dev->cdesc->bConfigurationValue;
		for (i = 0; i < nifaces; i++)
			ifaces[i] = &dev->ifaces[i];
		uaa.ifaces = ifaces;
		uaa.nifaces = nifaces;
		dev->subdevs = kmalloc((nifaces+1) * sizeof(device_t), M_USB,
				       M_WAITOK);
		dev->ifacenums = kmalloc((nifaces) * sizeof(*dev->ifacenums),
					 M_USB, M_WAITOK);

		found = 0;
		for (i = 0; i < nifaces; i++) {
			if (ifaces[i] == NULL)
				continue; /* interface already claimed */
			uaa.iface = ifaces[i];
			uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber;
			dev->subdevs[found] = bdev;
			dev->subdevs[found + 1] = 0;
			dev->ifacenums[found] = i;
			*uaap = uaa;
			usbd_devinfo(dev, 1, devinfo);
			device_set_desc_copy(bdev, devinfo);
			if (device_probe_and_attach(bdev) == 0) {
				ifaces[i] = 0; /* consumed */
				found++;

				/* create another child for the next iface */
				bdev = device_add_child(parent, NULL, -1);
				if (!bdev) {
					device_printf(parent,
					    "Device add failed\n");
					kfree(devinfo, M_USB);
					return (USBD_NORMAL_COMPLETION);
				}
				uaap = kmalloc(sizeof(uaa), M_USB, M_WAITOK);
				device_set_ivars(bdev, uaap);
			} else {
				dev->subdevs[found] = 0;
			}
		}
		if (found != 0) {
			/* remove the last created child.  It is unused */
			kfree(uaap, M_USB);
			kfree(devinfo, M_USB);
			device_delete_child(parent, bdev);
			/* kfree(uaap, M_USB); */ /* May be needed? xxx */
			return (USBD_NORMAL_COMPLETION);
		}
		tmpdv = dev->subdevs;
		dev->subdevs = NULL;
		kfree(tmpdv, M_USB);
		kfree(dev->ifacenums, M_USB);
		dev->ifacenums = NULL;
	}
	/* No interfaces were attached in any of the configurations. */

	if (dd->bNumConfigurations > 1) /* don't change if only 1 config */
		usbd_set_config_index(dev, 0, 0);

	DPRINTF(("usbd_probe_and_attach: no interface drivers found\n"));

	/* Finally try the generic driver. */
	uaa.iface = NULL;
	uaa.usegeneric = 1;
	uaa.configno = UHUB_UNK_CONFIGURATION;
	uaa.ifaceno = UHUB_UNK_INTERFACE;
	dev->subdevs = kmalloc(2 * sizeof(device_t), M_USB, M_WAITOK);
	dev->subdevs[0] = bdev;
	dev->subdevs[1] = 0;
	*uaap = uaa;
	usbd_devinfo(dev, 1, devinfo);
	device_set_desc_copy(bdev, devinfo);
	kfree(devinfo, M_USB);
	if (device_probe_and_attach(bdev) == 0)
		return (USBD_NORMAL_COMPLETION);

	/*
	 * The generic attach failed, but leave the device as it is.
	 * We just did not find any drivers, that's all.  The device is
	 * fully operational and not harming anyone.
	 */
	DPRINTF(("usbd_probe_and_attach: generic attach failed\n"));
 	return (USBD_NORMAL_COMPLETION);
}