xref: /openbsd/sys/dev/usb/ucrcom.c (revision 4bdff4be)
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