xref: /openbsd/sys/dev/usb/uark.c (revision 74ae6390)
1 /*	$OpenBSD: uark.c,v 1.24 2016/09/02 09:14:59 mpi Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Jonathan Gray <jsg@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 #ifdef UARK_DEBUG
33 #define DPRINTFN(n, x)  do { if (uarkdebug > (n)) printf x; } while (0)
34 int	uarkebug = 0;
35 #else
36 #define DPRINTFN(n, x)
37 #endif
38 #define DPRINTF(x) DPRINTFN(0, x)
39 
40 #define UARKBUFSZ		256
41 #define UARK_IFACE_NO		0
42 
43 #define UARK_SET_DATA_BITS(x)	(x - 5)
44 
45 #define UARK_PARITY_NONE	0x00
46 #define UARK_PARITY_ODD		0x08
47 #define UARK_PARITY_EVEN	0x18
48 
49 #define UARK_STOP_BITS_1	0x00
50 #define UARK_STOP_BITS_2	0x04
51 
52 #define UARK_BAUD_REF		3000000
53 
54 #define UARK_WRITE		0x40
55 #define UARK_READ		0xc0
56 
57 #define UARK_REQUEST		0xfe
58 
59 struct uark_softc {
60 	struct device		 sc_dev;
61 	struct usbd_device	*sc_udev;
62 	struct usbd_interface	*sc_iface;
63 	struct device 		*sc_subdev;
64 
65 	u_char			 sc_msr;
66 	u_char			 sc_lsr;
67 };
68 
69 void	uark_get_status(void *, int portno, u_char *lsr, u_char *msr);
70 void	uark_set(void *, int, int, int);
71 int	uark_param(void *, int, struct termios *);
72 void	uark_break(void *, int, int);
73 int	uark_cmd(struct uark_softc *, uint16_t, uint16_t);
74 
75 struct ucom_methods uark_methods = {
76 	uark_get_status,
77 	uark_set,
78 	uark_param,
79 	NULL,
80 	NULL,
81 	NULL,
82 	NULL,
83 	NULL,
84 };
85 
86 static const struct usb_devno uark_devs[] = {
87 	{ USB_VENDOR_ARKMICRO,		USB_PRODUCT_ARKMICRO_ARK3116 }
88 };
89 
90 int uark_match(struct device *, void *, void *);
91 void uark_attach(struct device *, struct device *, void *);
92 int uark_detach(struct device *, int);
93 
94 struct cfdriver uark_cd = {
95 	NULL, "uark", DV_DULL
96 };
97 
98 const struct cfattach uark_ca = {
99 	sizeof(struct uark_softc), uark_match, uark_attach, uark_detach
100 };
101 
102 int
103 uark_match(struct device *parent, void *match, void *aux)
104 {
105 	struct usb_attach_arg *uaa = aux;
106 
107 	if (uaa->iface == NULL)
108 		return UMATCH_NONE;
109 
110 	return (usb_lookup(uark_devs, uaa->vendor, uaa->product) != NULL) ?
111 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
112 }
113 
114 void
115 uark_attach(struct device *parent, struct device *self, void *aux)
116 {
117 	struct uark_softc *sc = (struct uark_softc *)self;
118 	struct usb_attach_arg *uaa = aux;
119 	struct ucom_attach_args uca;
120 	usb_interface_descriptor_t *id;
121 	usb_endpoint_descriptor_t *ed;
122 	usbd_status error;
123 	int i;
124 
125 	bzero(&uca, sizeof(uca));
126 	sc->sc_udev = uaa->device;
127 
128 	/* get the first interface handle */
129 	error = usbd_device2interface_handle(sc->sc_udev, UARK_IFACE_NO,
130 	    &sc->sc_iface);
131 	if (error != 0) {
132 		printf("%s: could not get interface handle\n",
133 		    sc->sc_dev.dv_xname);
134 		usbd_deactivate(sc->sc_udev);
135 		return;
136 	}
137 
138 	id = usbd_get_interface_descriptor(sc->sc_iface);
139 
140 	uca.bulkin = uca.bulkout = -1;
141 	for (i = 0; i < id->bNumEndpoints; i++) {
142 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
143 		if (ed == NULL) {
144 			printf("%s: no endpoint descriptor found for %d\n",
145 			    sc->sc_dev.dv_xname, i);
146 			usbd_deactivate(sc->sc_udev);
147 			return;
148 		}
149 
150 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
151 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
152 			uca.bulkin = ed->bEndpointAddress;
153 		else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
154 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
155 			uca.bulkout = ed->bEndpointAddress;
156 	}
157 
158 	if (uca.bulkin == -1 || uca.bulkout == -1) {
159 		printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
160 		usbd_deactivate(sc->sc_udev);
161 		return;
162 	}
163 
164 	uca.ibufsize = UARKBUFSZ;
165 	uca.obufsize = UARKBUFSZ;
166 	uca.ibufsizepad = UARKBUFSZ;
167 	uca.opkthdrlen = 0;
168 	uca.device = sc->sc_udev;
169 	uca.iface = sc->sc_iface;
170 	uca.methods = &uark_methods;
171 	uca.arg = sc;
172 	uca.info = NULL;
173 
174 	sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
175 }
176 
177 int
178 uark_detach(struct device *self, int flags)
179 {
180 	struct uark_softc *sc = (struct uark_softc *)self;
181 	int rv = 0;
182 
183 	if (sc->sc_subdev != NULL) {
184 		rv = config_detach(sc->sc_subdev, flags);
185 		sc->sc_subdev = NULL;
186 	}
187 
188 	return (rv);
189 }
190 
191 void
192 uark_set(void *vsc, int portno, int reg, int onoff)
193 {
194 	struct uark_softc *sc = vsc;
195 
196 	switch (reg) {
197 	case UCOM_SET_BREAK:
198 		uark_break(sc, portno, onoff);
199 		return;
200 	case UCOM_SET_DTR:
201 	case UCOM_SET_RTS:
202 	default:
203 		return;
204 	}
205 }
206 
207 int
208 uark_param(void *vsc, int portno, struct termios *t)
209 {
210 	struct uark_softc *sc = (struct uark_softc *)vsc;
211 	int data;
212 
213 	switch (t->c_ospeed) {
214 	case 300:
215 	case 600:
216 	case 1200:
217 	case 1800:
218 	case 2400:
219 	case 4800:
220 	case 9600:
221 	case 19200:
222 	case 38400:
223 	case 57600:
224 	case 115200:
225 		uark_cmd(sc, 3, 0x83);
226 		uark_cmd(sc, 0, (UARK_BAUD_REF / t->c_ospeed) & 0xFF);
227 		uark_cmd(sc, 1, (UARK_BAUD_REF / t->c_ospeed) >> 8);
228 		uark_cmd(sc, 3, 0x03);
229 		break;
230 	default:
231 		return (EINVAL);
232 	}
233 
234 	if (ISSET(t->c_cflag, CSTOPB))
235 		data = UARK_STOP_BITS_2;
236 	else
237 		data = UARK_STOP_BITS_1;
238 
239 	if (ISSET(t->c_cflag, PARENB)) {
240 		if (ISSET(t->c_cflag, PARODD))
241 			data |= UARK_PARITY_ODD;
242 		else
243 			data |= UARK_PARITY_EVEN;
244 	} else
245 		data |= UARK_PARITY_NONE;
246 
247 	switch (ISSET(t->c_cflag, CSIZE)) {
248 	case CS5:
249 		data |= UARK_SET_DATA_BITS(5);
250 		break;
251 	case CS6:
252 		data |= UARK_SET_DATA_BITS(6);
253 		break;
254 	case CS7:
255 		data |= UARK_SET_DATA_BITS(7);
256 		break;
257 	case CS8:
258 		data |= UARK_SET_DATA_BITS(8);
259 		break;
260 	}
261 
262 	uark_cmd(sc, 3, 0x00);
263 	uark_cmd(sc, 3, data);
264 
265 #if 0
266 	/* XXX flow control */
267 	if (ISSET(t->c_cflag, CRTSCTS))
268 		/*  rts/cts flow ctl */
269 	} else if (ISSET(t->c_iflag, IXON|IXOFF)) {
270 		/*  xon/xoff flow ctl */
271 	} else {
272 		/* disable flow ctl */
273 	}
274 #endif
275 
276 	return (0);
277 }
278 
279 void
280 uark_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
281 {
282 	struct uark_softc *sc = vsc;
283 
284 	if (msr != NULL)
285 		*msr = sc->sc_msr;
286 	if (lsr != NULL)
287 		*lsr = sc->sc_lsr;
288 }
289 
290 void
291 uark_break(void *vsc, int portno, int onoff)
292 {
293 #ifdef UARK_DEBUG
294 	struct uark_softc *sc = vsc;
295 
296 	printf("%s: break %s!\n", sc->sc_dev.dv_xname,
297 	    onoff ? "on" : "off");
298 
299 	if (onoff)
300 		/* break on */
301 		uark_cmd(sc, 4, 0x01);
302 	else
303 		uark_cmd(sc, 4, 0x00);
304 #endif
305 }
306 
307 int
308 uark_cmd(struct uark_softc *sc, uint16_t index, uint16_t value)
309 {
310 	usb_device_request_t req;
311 	usbd_status err;
312 
313 	req.bmRequestType = UARK_WRITE;
314 	req.bRequest = UARK_REQUEST;
315 	USETW(req.wValue, value);
316 	USETW(req.wIndex, index);
317 	USETW(req.wLength, 0);
318 	err = usbd_do_request(sc->sc_udev, &req, NULL);
319 
320 	if (err)
321 		return (EIO);
322 
323 	return (0);
324 }
325