Edit

IABSD.fr/src/sys/dev/usb/uscom.c

Branch :

  • Show log

    Commit

  • Author : patrick
    Date : 2019-02-24 17:36:28
    Hash : 90f3beec
    Message : Dynastream ANTUSB-2 works well on uscom(4), from Jan Klemkow.

  • sys/dev/usb/uscom.c
  • /*	$OpenBSD: uscom.c,v 1.7 2019/02/24 17:36:28 patrick Exp $	*/
    
    /*
     * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    #include <sys/param.h>
    #include <sys/systm.h>
    #include <sys/kernel.h>
    #include <sys/conf.h>
    #include <sys/tty.h>
    #include <sys/device.h>
    
    #include <dev/usb/usb.h>
    #include <dev/usb/usbdi.h>
    #include <dev/usb/usbdi_util.h>
    #include <dev/usb/usbdevs.h>
    
    #include <dev/usb/ucomvar.h>
    
    #define USCOMBUFSZ		256
    #define USCOM_IFACE_NO		0
    
    struct uscom_softc {
    	struct device		 sc_dev;
    	struct usbd_device	*sc_udev;
    	struct usbd_interface	*sc_iface;
    	struct device		*sc_subdev;
    };
    
    struct ucom_methods uscom_methods = {
    	NULL,
    	NULL,
    	NULL,
    	NULL,
    	NULL,
    	NULL,
    	NULL,
    	NULL,
    };
    
    static const struct usb_devno uscom_devs[] = {
    	{ USB_VENDOR_HP,		USB_PRODUCT_HP_HPX9GP },
    	{ USB_VENDOR_DYNASTREAM,	USB_PRODUCT_DYNASTREAM_ANTUSB2 },
    	{ USB_VENDOR_DYNASTREAM,	USB_PRODUCT_DYNASTREAM_ANTUSBM }
    };
    
    int	 uscom_match(struct device *, void *, void *);
    void	 uscom_attach(struct device *, struct device *, void *);
    int	 uscom_detach(struct device *, int);
    
    struct cfdriver uscom_cd = {
    	NULL, "uscom", DV_DULL
    };
    
    const struct cfattach uscom_ca = {
    	sizeof(struct uscom_softc), uscom_match, uscom_attach, uscom_detach
    };
    
    int
    uscom_match(struct device *parent, void *match, void *aux)
    {
    	struct usb_attach_arg *uaa = aux;
    
    	if (uaa->iface == NULL)
    		return UMATCH_NONE;
    
    	return (usb_lookup(uscom_devs, uaa->vendor, uaa->product) != NULL) ?
    	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
    }
    
    void
    uscom_attach(struct device *parent, struct device *self, void *aux)
    {
    	struct uscom_softc *sc = (struct uscom_softc *)self;
    	struct usb_attach_arg *uaa = aux;
    	struct ucom_attach_args uca;
    	usb_interface_descriptor_t *id;
    	usb_endpoint_descriptor_t *ed;
    	usbd_status error;
    	int i;
    
    	bzero(&uca, sizeof(uca));
    	sc->sc_udev = uaa->device;
    
    	/* get the first interface handle */
    	error = usbd_device2interface_handle(sc->sc_udev, USCOM_IFACE_NO,
    	    &sc->sc_iface);
    	if (error != 0) {
    		printf("%s: could not get interface handle\n",
    		    sc->sc_dev.dv_xname);
    		usbd_deactivate(sc->sc_udev);
    		return;
    	}
    
    	id = usbd_get_interface_descriptor(sc->sc_iface);
    
    	uca.bulkin = uca.bulkout = -1;
    	for (i = 0; i < id->bNumEndpoints; i++) {
    		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
    		if (ed == NULL) {
    			printf("%s: no endpoint descriptor found for %d\n",
    			    sc->sc_dev.dv_xname, i);
    			usbd_deactivate(sc->sc_udev);
    			return;
    		}
    
    		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
    			uca.bulkin = ed->bEndpointAddress;
    		else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
    			uca.bulkout = ed->bEndpointAddress;
    	}
    
    	if (uca.bulkin == -1 || uca.bulkout == -1) {
    		printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
    		usbd_deactivate(sc->sc_udev);
    		return;
    	}
    
    	uca.ibufsize = USCOMBUFSZ;
    	uca.obufsize = USCOMBUFSZ;
    	uca.ibufsizepad = USCOMBUFSZ;
    	uca.opkthdrlen = 0;
    	uca.device = sc->sc_udev;
    	uca.iface = sc->sc_iface;
    	uca.methods = &uscom_methods;
    	uca.arg = sc;
    	uca.info = NULL;
    	
    	sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
    }
    
    int
    uscom_detach(struct device *self, int flags)
    {
    	struct uscom_softc *sc = (struct uscom_softc *)self;
    	int rv = 0;
    
    	if (sc->sc_subdev != NULL) {
    		rv = config_detach(sc->sc_subdev, flags);
    		sc->sc_subdev = NULL;
    	}
    
    	return (rv);
    }