1 /* $OpenBSD: ucrcom.c,v 1.2 2022/04/09 20:07:44 naddy Exp $ */ 2 3 /* 4 * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/kernel.h> 22 #include <sys/tty.h> 23 #include <sys/device.h> 24 25 #include <dev/usb/usb.h> 26 #include <dev/usb/usbdi.h> 27 #include <dev/usb/usbdi_util.h> 28 #include <dev/usb/usbdevs.h> 29 30 #include <dev/usb/ucomvar.h> 31 32 #define UCRCOMBUFSZ 64 33 34 struct ucrcom_softc { 35 struct device sc_dev; 36 struct device *sc_subdev; 37 }; 38 39 const struct ucom_methods ucrcom_methods = { NULL }; 40 41 int ucrcom_match(struct device *, void *, void *); 42 void ucrcom_attach(struct device *, struct device *, void *); 43 int ucrcom_detach(struct device *, int); 44 45 struct cfdriver ucrcom_cd = { 46 NULL, "ucrcom", DV_DULL 47 }; 48 49 const struct cfattach ucrcom_ca = { 50 sizeof(struct ucrcom_softc), ucrcom_match, ucrcom_attach, ucrcom_detach 51 }; 52 53 int 54 ucrcom_match(struct device *parent, void *match, void *aux) 55 { 56 struct usb_attach_arg *uaa = aux; 57 usb_interface_descriptor_t *id; 58 usb_device_descriptor_t *dd; 59 60 if (uaa->iface == NULL) 61 return UMATCH_NONE; 62 63 id = usbd_get_interface_descriptor(uaa->iface); 64 dd = usbd_get_device_descriptor(uaa->device); 65 if (id == NULL || dd == NULL) 66 return UMATCH_NONE; 67 68 if (UGETW(dd->idVendor) == USB_VENDOR_GOOGLE && 69 id->bInterfaceClass == UICLASS_VENDOR && 70 id->bInterfaceSubClass == 0x50 && 71 id->bInterfaceProtocol == 1) 72 return UMATCH_VENDOR_IFACESUBCLASS_IFACEPROTO; 73 74 return UMATCH_NONE; 75 } 76 77 void 78 ucrcom_attach(struct device *parent, struct device *self, void *aux) 79 { 80 struct ucrcom_softc *sc = (struct ucrcom_softc *)self; 81 struct usb_attach_arg *uaa = aux; 82 struct ucom_attach_args uca; 83 usb_interface_descriptor_t *id; 84 usb_endpoint_descriptor_t *ed; 85 int i; 86 87 id = usbd_get_interface_descriptor(uaa->iface); 88 89 memset(&uca, 0, sizeof(uca)); 90 uca.bulkin = uca.bulkout = -1; 91 for (i = 0; i < id->bNumEndpoints; i++) { 92 ed = usbd_interface2endpoint_descriptor(uaa->iface, i); 93 if (ed == NULL) { 94 printf("%s: no endpoint descriptor for %d\n", 95 sc->sc_dev.dv_xname, i); 96 usbd_deactivate(uaa->device); 97 return; 98 } 99 100 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 101 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 102 uca.bulkin = ed->bEndpointAddress; 103 else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 104 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 105 uca.bulkout = ed->bEndpointAddress; 106 } 107 108 if (uca.bulkin == -1 || uca.bulkout == -1) { 109 printf("%s: missing endpoint\n", sc->sc_dev.dv_xname); 110 usbd_deactivate(uaa->device); 111 return; 112 } 113 114 uca.ibufsize = UCRCOMBUFSZ; 115 uca.ibufsizepad = UCRCOMBUFSZ; 116 uca.obufsize = UCRCOMBUFSZ; 117 uca.opkthdrlen = 0; 118 uca.device = uaa->device; 119 uca.iface = uaa->iface; 120 uca.methods = &ucrcom_methods; 121 uca.arg = sc; 122 123 sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); 124 } 125 126 int 127 ucrcom_detach(struct device *self, int flags) 128 { 129 struct ucrcom_softc *sc = (struct ucrcom_softc *)self; 130 int rv = 0; 131 132 if (sc->sc_subdev != NULL) 133 rv = config_detach(sc->sc_subdev, flags); 134 135 return rv; 136 } 137