File:  [DragonFly] / src / sys / dev / usbmisc / uvisor / uvisor.c
Revision 1.6: download - view: text, annotated - select for diffs
Wed Feb 11 15:13:06 2004 UTC (10 years, 8 months ago) by joerg
Branches: MAIN
CVS tags: HEAD
Add defined(__FreeBSD__) and defined(__DragonFly__) where appropiriate.

    1: /*
    2:  * $NetBSD: uvisor.c,v 1.9 2001/01/23 14:04:14 augustss Exp $
    3:  * $FreeBSD: src/sys/dev/usb/uvisor.c,v 1.16 2003/11/08 11:23:07 joe Exp $
    4:  * $DragonFly: src/sys/dev/usbmisc/uvisor/uvisor.c,v 1.6 2004/02/11 15:13:06 joerg Exp $
    5:  */
    6: 
    7: /*
    8:  * Also already merged from NetBSD:
    9:  *    $NetBSD: uvisor.c,v 1.12 2001/11/13 06:24:57 lukem Exp $
   10:  *    $NetBSD: uvisor.c,v 1.13 2002/02/11 15:11:49 augustss Exp $
   11:  *    $NetBSD: uvisor.c,v 1.14 2002/02/27 23:00:03 augustss Exp $
   12:  *    $NetBSD: uvisor.c,v 1.15 2002/06/16 15:01:31 augustss Exp $
   13:  *    $NetBSD: uvisor.c,v 1.16 2002/07/11 21:14:36 augustss Exp $
   14:  *    $NetBSD: uvisor.c,v 1.17 2002/08/13 11:38:15 augustss Exp $
   15:  *    $NetBSD: uvisor.c,v 1.18 2003/02/05 00:50:14 augustss Exp $
   16:  *    $NetBSD: uvisor.c,v 1.19 2003/02/07 18:12:37 augustss Exp $
   17:  *    $NetBSD: uvisor.c,v 1.20 2003/04/11 01:30:10 simonb Exp $
   18:  */
   19: 
   20: /*
   21:  * Copyright (c) 2000 The NetBSD Foundation, Inc.
   22:  * All rights reserved.
   23:  *
   24:  * This code is derived from software contributed to The NetBSD Foundation
   25:  * by Lennart Augustsson (lennart@augustsson.net) at
   26:  * Carlstedt Research & Technology.
   27:  *
   28:  * Redistribution and use in source and binary forms, with or without
   29:  * modification, are permitted provided that the following conditions
   30:  * are met:
   31:  * 1. Redistributions of source code must retain the above copyright
   32:  *    notice, this list of conditions and the following disclaimer.
   33:  * 2. Redistributions in binary form must reproduce the above copyright
   34:  *    notice, this list of conditions and the following disclaimer in the
   35:  *    documentation and/or other materials provided with the distribution.
   36:  * 3. All advertising materials mentioning features or use of this software
   37:  *    must display the following acknowledgement:
   38:  *        This product includes software developed by the NetBSD
   39:  *        Foundation, Inc. and its contributors.
   40:  * 4. Neither the name of The NetBSD Foundation nor the names of its
   41:  *    contributors may be used to endorse or promote products derived
   42:  *    from this software without specific prior written permission.
   43:  *
   44:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   45:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   46:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   47:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   48:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   49:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   50:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   51:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   52:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   53:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   54:  * POSSIBILITY OF SUCH DAMAGE.
   55:  */
   56: 
   57: /*
   58:  * Handspring Visor (Palmpilot compatible PDA) driver
   59:  */
   60: 
   61: #include <sys/param.h>
   62: #include <sys/systm.h>
   63: #include <sys/kernel.h>
   64: #if defined(__NetBSD__) || defined(__OpenBSD__)
   65: #include <sys/device.h>
   66: #elif defined(__FreeBSD__) || defined(__DragonFly__)
   67: #include <sys/bus.h>
   68: #endif
   69: #include <sys/conf.h>
   70: #include <sys/tty.h>
   71: #include <sys/sysctl.h>
   72: 
   73: #include <bus/usb/usb.h>
   74: #include <bus/usb/usbhid.h>
   75: 
   76: #include <bus/usb/usbdi.h>
   77: #include <bus/usb/usbdi_util.h>
   78: #include <bus/usb/usbdevs.h>
   79: 
   80: #include "../ucom/ucomvar.h"
   81: 
   82: #ifdef USB_DEBUG
   83: #define DPRINTF(x)	if (uvisordebug) printf x
   84: #define DPRINTFN(n,x)	if (uvisordebug>(n)) printf x
   85: int uvisordebug = 0;
   86: SYSCTL_NODE(_hw_usb, OID_AUTO, uvisor, CTLFLAG_RW, 0, "USB uvisor");
   87: SYSCTL_INT(_hw_usb_uvisor, OID_AUTO, debug, CTLFLAG_RW,
   88: 	   &uvisordebug, 0, "uvisor debug level");
   89: #else
   90: #define DPRINTF(x)
   91: #define DPRINTFN(n,x)
   92: #endif
   93: 
   94: #define UVISOR_CONFIG_INDEX	0
   95: #define UVISOR_IFACE_INDEX	0
   96: #define UVISOR_MODVER		1
   97: 
   98: /* From the Linux driver */
   99: /*
  100:  * UVISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that
  101:  * are available to be transfered to the host for the specified endpoint.
  102:  * Currently this is not used, and always returns 0x0001
  103:  */
  104: #define UVISOR_REQUEST_BYTES_AVAILABLE		0x01
  105: 
  106: /*
  107:  * UVISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host
  108:  * is now closing the pipe. An empty packet is sent in response.
  109:  */
  110: #define UVISOR_CLOSE_NOTIFICATION		0x02
  111: 
  112: /*
  113:  * UVISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to
  114:  * get the endpoints used by the connection.
  115:  */
  116: #define UVISOR_GET_CONNECTION_INFORMATION	0x03
  117: 
  118: 
  119: /*
  120:  * UVISOR_GET_CONNECTION_INFORMATION returns data in the following format
  121:  */
  122: #define UVISOR_MAX_CONN 8
  123: struct uvisor_connection_info {
  124: 	uWord	num_ports;
  125: 	struct {
  126: 		uByte	port_function_id;
  127: 		uByte	port;
  128: 	} connections[UVISOR_MAX_CONN];
  129: };
  130: #define UVISOR_CONNECTION_INFO_SIZE 18
  131: 
  132: /* struct uvisor_connection_info.connection[x].port defines: */
  133: #define UVISOR_ENDPOINT_1		0x01
  134: #define UVISOR_ENDPOINT_2		0x02
  135: 
  136: /* struct uvisor_connection_info.connection[x].port_function_id defines: */
  137: #define UVISOR_FUNCTION_GENERIC		0x00
  138: #define UVISOR_FUNCTION_DEBUGGER	0x01
  139: #define UVISOR_FUNCTION_HOTSYNC		0x02
  140: #define UVISOR_FUNCTION_CONSOLE		0x03
  141: #define UVISOR_FUNCTION_REMOTE_FILE_SYS	0x04
  142: 
  143: /*
  144:  * Unknown PalmOS stuff.
  145:  */
  146: #define UVISOR_GET_PALM_INFORMATION		0x04
  147: #define UVISOR_GET_PALM_INFORMATION_LEN		0x14
  148: 
  149: 
  150: /*
  151:  * Crank down UVISORBUFSIZE from 1024 to 64 to avoid a problem where
  152:  * the Palm device and the USB host controller deadlock. The USB host
  153:  * controller is expecting an early-end-of-transmission packet with 0
  154:  * data, and the Palm doesn't send one because it's already
  155:  * communicated the amount of data it's going to send in a header
  156:  * (which ucom/uvisor are oblivious to). This is the problem that has
  157:  * been known on the pilot-link lists as the "[Free]BSD USB problem",
  158:  * but not understood.
  159:  */
  160: #define UVISORIBUFSIZE 64
  161: #define UVISOROBUFSIZE 1024
  162: 
  163: struct uvisor_softc {
  164: 	struct ucom_softc	sc_ucom;
  165: 	u_int16_t		sc_flags;
  166: };
  167: 
  168: Static usbd_status uvisor_init(struct uvisor_softc *);
  169: 
  170: Static void uvisor_close(void *, int);
  171: 
  172: struct ucom_callback uvisor_callback = {
  173: 	NULL,
  174: 	NULL,
  175: 	NULL,
  176: 	NULL,
  177: 	NULL,
  178: 	uvisor_close,
  179: 	NULL,
  180: 	NULL,
  181: };
  182: 
  183: Static device_probe_t uvisor_match;
  184: Static device_attach_t uvisor_attach;
  185: Static device_detach_t uvisor_detach;
  186: Static device_method_t uvisor_methods[] = {
  187:        /* Device interface */
  188:        DEVMETHOD(device_probe, uvisor_match),
  189:        DEVMETHOD(device_attach, uvisor_attach),
  190:        DEVMETHOD(device_detach, uvisor_detach),
  191:        { 0, 0 }
  192:  };
  193: 
  194: 
  195: Static driver_t uvisor_driver = {
  196:        "ucom",
  197:        uvisor_methods,
  198:        sizeof (struct uvisor_softc)
  199: };
  200: 
  201: DRIVER_MODULE(uvisor, uhub, uvisor_driver, ucom_devclass, usbd_driver_load, 0);
  202: MODULE_DEPEND(uvisor, usb, 1, 1, 1);
  203: MODULE_DEPEND(uvisor, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
  204: MODULE_VERSION(uvisor, UVISOR_MODVER);
  205: 
  206: struct uvisor_type {
  207: 	struct usb_devno	uv_dev;
  208: 	u_int16_t		uv_flags;
  209: #define PALM4	0x0001
  210: };
  211: static const struct uvisor_type uvisor_devs[] = {
  212: 	{{ USB_VENDOR_HANDSPRING, USB_PRODUCT_HANDSPRING_VISOR }, 0 },
  213: 	{{ USB_VENDOR_HANDSPRING, USB_PRODUCT_HANDSPRING_TREO }, PALM4 },
  214: 	{{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M500 }, PALM4 },
  215: 	{{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M505 }, PALM4 },
  216: 	{{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M515 }, PALM4 },
  217: 	{{ USB_VENDOR_PALM, USB_PRODUCT_PALM_I705 }, PALM4 },
  218: 	{{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M125 }, PALM4 },
  219: 	{{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M130 }, PALM4 },
  220: 	{{ USB_VENDOR_PALM, USB_PRODUCT_PALM_TUNGSTEN_Z }, PALM4 },
  221: 	{{ USB_VENDOR_PALM, USB_PRODUCT_PALM_TUNGSTEN_T }, PALM4 },
  222: 	{{ USB_VENDOR_PALM, USB_PRODUCT_PALM_ZIRE }, PALM4 },
  223: 	{{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_40 }, 0 },
  224: 	{{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_41 }, 0 },
  225: 	{{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_S360 }, PALM4 },
  226: 	{{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_NX60 }, PALM4 },
  227: /*	{{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_25 }, PALM4 },*/
  228: };
  229: #define uvisor_lookup(v, p) ((const struct uvisor_type *)usb_lookup(uvisor_devs, v, p))
  230: 
  231: 
  232: USB_MATCH(uvisor)
  233: {
  234: 	USB_MATCH_START(uvisor, uaa);
  235: 
  236: 	if (uaa->iface != NULL)
  237: 		return (UMATCH_NONE);
  238: 
  239: 	DPRINTFN(20,("uvisor: vendor=0x%x, product=0x%x\n",
  240: 		     uaa->vendor, uaa->product));
  241: 
  242: 	return (uvisor_lookup(uaa->vendor, uaa->product) != NULL ?
  243: 		UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
  244: }
  245: 
  246: USB_ATTACH(uvisor)
  247: {
  248: 	USB_ATTACH_START(uvisor, sc, uaa);
  249: 	usbd_device_handle dev = uaa->device;
  250: 	usbd_interface_handle iface;
  251: 	usb_interface_descriptor_t *id;
  252: 	usb_endpoint_descriptor_t *ed;
  253: 	char *devinfo;
  254: 	const char *devname;
  255: 	int i;
  256: 	usbd_status err;
  257: 	struct ucom_softc *ucom;
  258: 
  259: 	devinfo = malloc(1024, M_USBDEV, M_WAITOK);
  260: 	ucom = &sc->sc_ucom;
  261: 
  262: 	bzero(sc, sizeof (struct uvisor_softc));
  263: 	usbd_devinfo(dev, 0, devinfo);
  264: 
  265: 	ucom->sc_dev = self;
  266: 	device_set_desc_copy(self, devinfo);
  267: 
  268: 	ucom->sc_udev = dev;
  269: 	ucom->sc_iface = uaa->iface;
  270: 
  271: 	devname = USBDEVNAME(ucom->sc_dev);
  272: 	printf("%s: %s\n", devname, devinfo);
  273: 
  274: 	DPRINTFN(10,("\nuvisor_attach: sc=%p\n", sc));
  275: 
  276: 	/* Move the device into the configured state. */
  277: 	err = usbd_set_config_index(dev, UVISOR_CONFIG_INDEX, 1);
  278: 	if (err) {
  279: 		printf("\n%s: failed to set configuration, err=%s\n",
  280: 		       devname, usbd_errstr(err));
  281: 		goto bad;
  282: 	}
  283: 
  284: 	err = usbd_device2interface_handle(dev, UVISOR_IFACE_INDEX, &iface);
  285: 	if (err) {
  286: 		printf("\n%s: failed to get interface, err=%s\n",
  287: 		       devname, usbd_errstr(err));
  288: 		goto bad;
  289: 	}
  290: 
  291: 	printf("%s: %s\n", devname, devinfo);
  292: 
  293: 	sc->sc_flags = uvisor_lookup(uaa->vendor, uaa->product)->uv_flags;
  294: 
  295: 	id = usbd_get_interface_descriptor(iface);
  296: 
  297: 	ucom->sc_udev = dev;
  298: 	ucom->sc_iface = iface;
  299: 
  300: 	ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
  301: 	for (i = 0; i < id->bNumEndpoints; i++) {
  302: 		int addr, dir, attr;
  303: 		ed = usbd_interface2endpoint_descriptor(iface, i);
  304: 		if (ed == NULL) {
  305: 			printf("%s: could not read endpoint descriptor"
  306: 			       ": %s\n", devname, usbd_errstr(err));
  307: 			goto bad;
  308: 		}
  309: 
  310: 		addr = ed->bEndpointAddress;
  311: 		dir = UE_GET_DIR(ed->bEndpointAddress);
  312: 		attr = ed->bmAttributes & UE_XFERTYPE;
  313: 		if (dir == UE_DIR_IN && attr == UE_BULK)
  314: 			ucom->sc_bulkin_no = addr;
  315: 		else if (dir == UE_DIR_OUT && attr == UE_BULK)
  316: 			ucom->sc_bulkout_no = addr;
  317: 		else {
  318: 			printf("%s: unexpected endpoint\n", devname);
  319: 			goto bad;
  320: 		}
  321: 	}
  322: 	if (ucom->sc_bulkin_no == -1) {
  323: 		printf("%s: Could not find data bulk in\n",
  324: 		       USBDEVNAME(ucom->sc_dev));
  325: 		goto bad;
  326: 	}
  327: 	if (ucom->sc_bulkout_no == -1) {
  328: 		printf("%s: Could not find data bulk out\n",
  329: 		       USBDEVNAME(ucom->sc_dev));
  330: 		goto bad;
  331: 	}
  332: 
  333: 	ucom->sc_parent = sc;
  334: 	ucom->sc_portno = UCOM_UNK_PORTNO;
  335: 	/* bulkin, bulkout set above */
  336: 	ucom->sc_ibufsize = UVISORIBUFSIZE;
  337: 	ucom->sc_obufsize = UVISOROBUFSIZE;
  338: 	ucom->sc_ibufsizepad = UVISORIBUFSIZE;
  339: 	ucom->sc_opkthdrlen = 0;
  340: 	ucom->sc_callback = &uvisor_callback;
  341: 
  342: 	err = uvisor_init(sc);
  343: 	if (err) {
  344: 		printf("%s: init failed, %s\n", USBDEVNAME(ucom->sc_dev),
  345: 		       usbd_errstr(err));
  346: 		goto bad;
  347: 	}
  348: 
  349: 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, ucom->sc_udev,
  350: 			   USBDEV(ucom->sc_dev));
  351: 
  352: 	DPRINTF(("uvisor: in=0x%x out=0x%x\n", ucom->sc_bulkin_no, ucom->sc_bulkout_no));
  353: 	ucom_attach(&sc->sc_ucom);
  354: 
  355: 	USB_ATTACH_SUCCESS_RETURN;
  356: 
  357: bad:
  358: 	DPRINTF(("uvisor_attach: ATTACH ERROR\n"));
  359: 	ucom->sc_dying = 1;
  360: 	USB_ATTACH_ERROR_RETURN;
  361: }
  362: 
  363: #if 0
  364: 
  365: int
  366: uvisor_activate(device_ptr_t self, enum devact act)
  367: {
  368: 	struct uvisor_softc *sc = (struct uvisor_softc *)self;
  369: 	int rv = 0;
  370: 
  371: 	switch (act) {
  372: 	case DVACT_ACTIVATE:
  373: 		return (EOPNOTSUPP);
  374: 		break;
  375: 
  376: 	case DVACT_DEACTIVATE:
  377: 		if (sc->sc_subdev != NULL)
  378: 			rv = config_deactivate(sc->sc_subdev);
  379: 		sc->sc_dying = 1;
  380: 		break;
  381: 	}
  382: 	return (rv);
  383: }
  384: 
  385: #endif
  386: 
  387: USB_DETACH(uvisor)
  388: {
  389: 	USB_DETACH_START(uvisor, sc);
  390: 	int rv = 0;
  391: 
  392: 	DPRINTF(("uvisor_detach: sc=%p\n", sc));
  393: 	sc->sc_ucom.sc_dying = 1;
  394: 	rv = ucom_detach(&sc->sc_ucom);
  395: 
  396: 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_ucom.sc_udev,
  397: 			   USBDEV(sc->sc_ucom.sc_dev));
  398: 
  399: 	return (rv);
  400: }
  401: 
  402: usbd_status
  403: uvisor_init(struct uvisor_softc *sc)
  404: {
  405: 	usbd_status err;
  406: 	usb_device_request_t req;
  407: 	struct uvisor_connection_info coninfo;
  408: 	int actlen;
  409: 	uWord avail;
  410: 	char buffer[256];
  411: 
  412: 	DPRINTF(("uvisor_init: getting connection info\n"));
  413: 	req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
  414: 	req.bRequest = UVISOR_GET_CONNECTION_INFORMATION;
  415: 	USETW(req.wValue, 0);
  416: 	USETW(req.wIndex, 0);
  417: 	USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE);
  418: 	err = usbd_do_request_flags(sc->sc_ucom.sc_udev, &req, &coninfo,
  419: 				    USBD_SHORT_XFER_OK, &actlen,
  420: 				    USBD_DEFAULT_TIMEOUT);
  421: 	if (err)
  422: 		return (err);
  423: 
  424: #ifdef USB_DEBUG
  425: 	{
  426: 		int i, np;
  427: 		char *string;
  428: 
  429: 		np = UGETW(coninfo.num_ports);
  430: 		printf("%s: Number of ports: %d\n", USBDEVNAME(sc->sc_ucom.sc_dev), np);
  431: 		for (i = 0; i < np; ++i) {
  432: 			switch (coninfo.connections[i].port_function_id) {
  433: 			case UVISOR_FUNCTION_GENERIC:
  434: 				string = "Generic";
  435: 				break;
  436: 			case UVISOR_FUNCTION_DEBUGGER:
  437: 				string = "Debugger";
  438: 				break;
  439: 			case UVISOR_FUNCTION_HOTSYNC:
  440: 				string = "HotSync";
  441: 				break;
  442: 			case UVISOR_FUNCTION_REMOTE_FILE_SYS:
  443: 				string = "Remote File System";
  444: 				break;
  445: 			default:
  446: 				string = "unknown";
  447: 				break;
  448: 			}
  449: 			printf("%s: port %d, is for %s\n",
  450: 			    USBDEVNAME(sc->sc_ucom.sc_dev), coninfo.connections[i].port,
  451: 			    string);
  452: 		}
  453: 	}
  454: #endif
  455: 
  456: 	if (sc->sc_flags & PALM4) {
  457: 		/* Palm OS 4.0 Hack */
  458: 		req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
  459: 		req.bRequest = UVISOR_GET_PALM_INFORMATION;
  460: 		USETW(req.wValue, 0);
  461: 		USETW(req.wIndex, 0);
  462: 		USETW(req.wLength, UVISOR_GET_PALM_INFORMATION_LEN);
  463: 		err = usbd_do_request(sc->sc_ucom.sc_udev, &req, buffer);
  464: 		if (err)
  465: 			return (err);
  466: 		req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
  467: 		req.bRequest = UVISOR_GET_PALM_INFORMATION;
  468: 		USETW(req.wValue, 0);
  469: 		USETW(req.wIndex, 0);
  470: 		USETW(req.wLength, UVISOR_GET_PALM_INFORMATION_LEN);
  471: 		err = usbd_do_request(sc->sc_ucom.sc_udev, &req, buffer);
  472: 		if (err)
  473: 			return (err);
  474: 	}
  475: 
  476: 	DPRINTF(("uvisor_init: getting available bytes\n"));
  477: 	req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
  478: 	req.bRequest = UVISOR_REQUEST_BYTES_AVAILABLE;
  479: 	USETW(req.wValue, 0);
  480: 	USETW(req.wIndex, 5);
  481: 	USETW(req.wLength, sizeof avail);
  482: 	err = usbd_do_request(sc->sc_ucom.sc_udev, &req, &avail);
  483: 	if (err)
  484: 		return (err);
  485: 	DPRINTF(("uvisor_init: avail=%d\n", UGETW(avail)));
  486: 
  487: 	DPRINTF(("uvisor_init: done\n"));
  488: 	return (err);
  489: }
  490: 
  491: void
  492: uvisor_close(void *addr, int portno)
  493: {
  494: 	struct uvisor_softc *sc = addr;
  495: 	usb_device_request_t req;
  496: 	struct uvisor_connection_info coninfo; /* XXX ? */
  497: 	int actlen;
  498: 
  499: 	if (sc->sc_ucom.sc_dying)
  500: 		return;
  501: 
  502: 	req.bmRequestType = UT_READ_VENDOR_ENDPOINT; /* XXX read? */
  503: 	req.bRequest = UVISOR_CLOSE_NOTIFICATION;
  504: 	USETW(req.wValue, 0);
  505: 	USETW(req.wIndex, 0);
  506: 	USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE);
  507: 	(void)usbd_do_request_flags(sc->sc_ucom.sc_udev, &req, &coninfo,
  508: 				    USBD_SHORT_XFER_OK, &actlen,
  509: 				    USBD_DEFAULT_TIMEOUT);
  510: }