1 /* $OpenBSD: umcs.c,v 1.12 2024/05/23 03:21:09 jsg Exp $ */
2 /* $NetBSD: umcs.c,v 1.8 2014/08/23 21:37:56 martin Exp $ */
3 /* $FreeBSD: head/sys/dev/usb/serial/umcs.c 260559 2014-01-12 11:44:28Z hselasky $ */
4
5 /*-
6 * Copyright (c) 2010 Lev Serebryakov <lev@FreeBSD.org>.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /*
32 * This driver supports several multiport USB-to-RS232 serial adapters driven
33 * by MosChip mos7820 and mos7840, bridge chips. The adapters are sold under
34 * many different brand names.
35 *
36 * Datasheets are available at MosChip www site at http://www.moschip.com.
37 * The datasheets don't contain full programming information for the chip.
38 *
39 * It is normal to have only two enabled ports in devices, based on quad-port
40 * mos7840.
41 */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/tty.h>
47 #include <sys/device.h>
48 #include <sys/task.h>
49
50 #include <dev/usb/usb.h>
51 #include <dev/usb/usbdi.h>
52 #include <dev/usb/usbdevs.h>
53
54 #include <dev/usb/ucomvar.h>
55
56 #include "umcs.h"
57
58 #ifdef UMCS_DEBUG
59 #define DPRINTF(x...) printf(x)
60 #else
61 #define DPRINTF(x...)
62 #endif
63
64 #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
65
66 /*
67 * Two-port devices (both with 7820 chip and 7840 chip configured as two-port)
68 * have ports 0 and 2, with ports 1 and 3 omitted.
69 * So, PHYSICAL port numbers on two-port device will be 0 and 2.
70 *
71 * We use an array of the following struct, indexed by ucom port index,
72 * and include the physical port number in it.
73 */
74 struct umcs_port {
75 struct ucom_softc *ucom; /* ucom subdevice */
76 unsigned int pn; /* physical port number */
77 int flags;
78 #define UMCS_STATCHG 0x01
79
80 uint8_t lcr; /* local line control reg. */
81 uint8_t mcr; /* local modem control reg. */
82 };
83
84 struct umcs_softc {
85 struct device sc_dev;
86 struct usbd_device *sc_udev; /* the usb device */
87 struct usbd_pipe *sc_ipipe; /* interrupt pipe */
88 uint8_t *sc_ibuf; /* buffer for interrupt xfer */
89 unsigned int sc_isize; /* size of buffer */
90
91 struct umcs_port sc_subdevs[UMCS_MAX_PORTS];
92 uint8_t sc_numports; /* number of ports */
93
94 int sc_init_done;
95 struct task sc_status_task;
96 };
97
98 int umcs_get_reg(struct umcs_softc *, uint8_t, uint8_t *);
99 int umcs_set_reg(struct umcs_softc *, uint8_t, uint8_t);
100 int umcs_get_uart_reg(struct umcs_softc *, uint8_t, uint8_t, uint8_t *);
101 int umcs_set_uart_reg(struct umcs_softc *, uint8_t, uint8_t, uint8_t);
102 int umcs_calc_baudrate(uint32_t, uint16_t *, uint8_t *);
103 int umcs_set_baudrate(struct umcs_softc *, uint8_t, uint32_t);
104 void umcs_dtr(struct umcs_softc *, int, int);
105 void umcs_rts(struct umcs_softc *, int, int);
106 void umcs_break(struct umcs_softc *, int, int);
107
108 int umcs_match(struct device *, void *, void *);
109 void umcs_attach(struct device *, struct device *, void *);
110 int umcs_detach(struct device *, int);
111 void umcs_intr(struct usbd_xfer *, void *, usbd_status);
112 void umcs_status_task(void *);
113
114 void umcs_get_status(void *, int, uint8_t *, uint8_t *);
115 void umcs_set(void *, int, int, int);
116 int umcs_param(void *, int, struct termios *);
117 int umcs_open(void *, int);
118 void umcs_close(void *, int);
119
120 const struct ucom_methods umcs_methods = {
121 umcs_get_status,
122 umcs_set,
123 umcs_param,
124 NULL,
125 umcs_open,
126 umcs_close,
127 NULL,
128 NULL,
129 };
130
131 const struct usb_devno umcs_devs[] = {
132 { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7810 },
133 { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7820 },
134 { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7840 },
135 { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC2324 }
136 };
137
138 struct cfdriver umcs_cd = {
139 NULL, "umcs", DV_DULL
140 };
141
142 const struct cfattach umcs_ca = {
143 sizeof(struct umcs_softc), umcs_match, umcs_attach, umcs_detach
144 };
145
146
147 static inline int
umcs_reg_sp(int pn)148 umcs_reg_sp(int pn)
149 {
150 KASSERT(pn >= 0 && pn < 4);
151 switch (pn) {
152 default:
153 case 0: return UMCS_SP1;
154 case 1: return UMCS_SP2;
155 case 2: return UMCS_SP3;
156 case 3: return UMCS_SP4;
157 }
158 }
159
160 static inline int
umcs_reg_ctrl(int pn)161 umcs_reg_ctrl(int pn)
162 {
163 KASSERT(pn >= 0 && pn < 4);
164 switch (pn) {
165 default:
166 case 0: return UMCS_CTRL1;
167 case 1: return UMCS_CTRL2;
168 case 2: return UMCS_CTRL3;
169 case 3: return UMCS_CTRL4;
170 }
171 }
172
173 int
umcs_match(struct device * dev,void * match,void * aux)174 umcs_match(struct device *dev, void *match, void *aux)
175 {
176 struct usb_attach_arg *uaa = aux;
177
178 if (uaa->iface == NULL || uaa->ifaceno != UMCS_IFACE_NO)
179 return (UMATCH_NONE);
180
181 return (usb_lookup(umcs_devs, uaa->vendor, uaa->product) != NULL) ?
182 UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
183 }
184
185 void
umcs_attach(struct device * parent,struct device * self,void * aux)186 umcs_attach(struct device *parent, struct device *self, void *aux)
187 {
188 struct umcs_softc *sc = (struct umcs_softc *)self;
189 struct usb_attach_arg *uaa = aux;
190 usb_interface_descriptor_t *id;
191 usb_endpoint_descriptor_t *ed;
192 struct ucom_attach_args uca;
193 int error, i, intr_addr;
194 uint8_t data;
195
196 sc->sc_udev = uaa->device;
197
198 /*
199 * Get number of ports
200 * Documentation (full datasheet) says, that number of ports is
201 * set as UMCS_MODE_SELECT24S bit in MODE R/Only
202 * register. But vendor driver uses these undocumented
203 * register & bit.
204 *
205 * Experiments show, that MODE register can have `0'
206 * (4 ports) bit on 2-port device, so use vendor driver's way.
207 *
208 * Also, see notes in header file for these constants.
209 */
210 if (umcs_get_reg(sc, UMCS_GPIO, &data)) {
211 printf("%s: unable to get number of ports\n", DEVNAME(sc));
212 usbd_deactivate(sc->sc_udev);
213 return;
214 }
215 if (data & UMCS_GPIO_4PORTS)
216 sc->sc_numports = 4; /* physical port no are : 0, 1, 2, 3 */
217 else if (uaa->product == USB_PRODUCT_MOSCHIP_MCS7810)
218 sc->sc_numports = 1;
219 else
220 sc->sc_numports = 2; /* physical port no are: 0 and 2 */
221
222 #ifdef UMCS_DEBUG
223 if (!umcs_get_reg(sc, UMCS_MODE, &data)) {
224 printf("%s: On-die configuration: RST: active %s, "
225 "HRD: %s, PLL: %s, POR: %s, Ports: %s, EEPROM write %s, "
226 "IrDA is %savailable\n", DEVNAME(sc),
227 (data & UMCS_MODE_RESET) ? "low" : "high",
228 (data & UMCS_MODE_SER_PRSNT) ? "yes" : "no",
229 (data & UMCS_MODE_PLLBYPASS) ? "bypassed" : "avail",
230 (data & UMCS_MODE_PORBYPASS) ? "bypassed" : "avail",
231 (data & UMCS_MODE_SELECT24S) ? "2" : "4",
232 (data & UMCS_MODE_EEPROMWR) ? "enabled" : "disabled",
233 (data & UMCS_MODE_IRDA) ? "" : "not ");
234 }
235 #endif
236
237 /* Set up the interrupt pipe */
238 id = usbd_get_interface_descriptor(uaa->iface);
239 intr_addr = -1;
240 for (i = 0 ; i < id->bNumEndpoints ; i++) {
241 ed = usbd_interface2endpoint_descriptor(uaa->iface, i);
242 if (ed == NULL) {
243 printf("%s: no endpoint descriptor found for %d\n",
244 DEVNAME(sc), i);
245 usbd_deactivate(sc->sc_udev);
246 return;
247 }
248
249 if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN ||
250 UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT)
251 continue;
252 sc->sc_isize = UGETW(ed->wMaxPacketSize);
253 intr_addr = ed->bEndpointAddress;
254 break;
255 }
256 if (intr_addr < 0) {
257 printf("%s: missing endpoint\n", DEVNAME(sc));
258 usbd_deactivate(sc->sc_udev);
259 return;
260 }
261 sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
262
263 error = usbd_open_pipe_intr(uaa->iface, intr_addr,
264 USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf,
265 sc->sc_isize, umcs_intr, 100 /* XXX */);
266 if (error) {
267 printf("%s: cannot open interrupt pipe (addr %d)\n",
268 DEVNAME(sc), intr_addr);
269 usbd_deactivate(sc->sc_udev);
270 return;
271 }
272
273 memset(&uca, 0, sizeof uca);
274 uca.ibufsize = 256;
275 uca.obufsize = 256;
276 uca.ibufsizepad = 256;
277 uca.opkthdrlen = 0;
278 uca.device = sc->sc_udev;
279 uca.iface = uaa->iface;
280 uca.methods = &umcs_methods;
281 uca.arg = sc;
282
283 for (i = 0; i < sc->sc_numports; i++) {
284 uca.bulkin = uca.bulkout = -1;
285
286 /*
287 * On 4 port cards, endpoints are 0/1, 2/3, 4/5, and 6/7.
288 * On 2 port cards, they are 0/1 and 4/5.
289 * On single port, just 0/1 will be used.
290 */
291 int pn = i * (sc->sc_numports == 2 ? 2 : 1);
292
293 ed = usbd_interface2endpoint_descriptor(uaa->iface, pn*2);
294 if (ed == NULL) {
295 printf("%s: no bulk in endpoint found for %d\n",
296 DEVNAME(sc), i);
297 usbd_deactivate(sc->sc_udev);
298 return;
299 }
300 uca.bulkin = ed->bEndpointAddress;
301
302 ed = usbd_interface2endpoint_descriptor(uaa->iface, pn*2+1);
303 if (ed == NULL) {
304 printf("%s: no bulk out endpoint found for %d\n",
305 DEVNAME(sc), i);
306 usbd_deactivate(sc->sc_udev);
307 return;
308 }
309 uca.bulkout = ed->bEndpointAddress;
310 uca.portno = i;
311
312 sc->sc_subdevs[i].pn = pn;
313 sc->sc_subdevs[i].ucom = (struct ucom_softc *)
314 config_found_sm(self, &uca, ucomprint, ucomsubmatch);
315 }
316
317 task_set(&sc->sc_status_task, umcs_status_task, sc);
318 }
319
320 int
umcs_get_reg(struct umcs_softc * sc,uint8_t reg,uint8_t * data)321 umcs_get_reg(struct umcs_softc *sc, uint8_t reg, uint8_t *data)
322 {
323 usb_device_request_t req;
324
325 req.bmRequestType = UT_READ_VENDOR_DEVICE;
326 req.bRequest = UMCS_READ;
327 USETW(req.wValue, 0);
328 USETW(req.wIndex, reg);
329 USETW(req.wLength, UMCS_READ_LENGTH);
330
331 if (usbd_do_request(sc->sc_udev, &req, data))
332 return (EIO);
333
334 return (0);
335 }
336
337 int
umcs_set_reg(struct umcs_softc * sc,uint8_t reg,uint8_t data)338 umcs_set_reg(struct umcs_softc *sc, uint8_t reg, uint8_t data)
339 {
340 usb_device_request_t req;
341
342 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
343 req.bRequest = UMCS_WRITE;
344 USETW(req.wValue, data);
345 USETW(req.wIndex, reg);
346 USETW(req.wLength, 0);
347
348 if (usbd_do_request(sc->sc_udev, &req, NULL))
349 return (EIO);
350
351 return (0);
352 }
353
354 int
umcs_get_uart_reg(struct umcs_softc * sc,uint8_t portno,uint8_t reg,uint8_t * data)355 umcs_get_uart_reg(struct umcs_softc *sc, uint8_t portno, uint8_t reg,
356 uint8_t *data)
357 {
358 usb_device_request_t req;
359 uint16_t wVal;
360
361 wVal = ((uint16_t)(sc->sc_subdevs[portno].pn + 1)) << 8;
362
363 req.bmRequestType = UT_READ_VENDOR_DEVICE;
364 req.bRequest = UMCS_READ;
365 USETW(req.wValue, wVal);
366 USETW(req.wIndex, reg);
367 USETW(req.wLength, UMCS_READ_LENGTH);
368
369 if (usbd_do_request(sc->sc_udev, &req, data))
370 return (EIO);
371
372 return (0);
373 }
374
375 int
umcs_set_uart_reg(struct umcs_softc * sc,uint8_t portno,uint8_t reg,uint8_t data)376 umcs_set_uart_reg(struct umcs_softc *sc, uint8_t portno, uint8_t reg,
377 uint8_t data)
378 {
379 usb_device_request_t req;
380 uint16_t wVal;
381
382 wVal = ((uint16_t)(sc->sc_subdevs[portno].pn + 1)) << 8 | data;
383
384 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
385 req.bRequest = UMCS_WRITE;
386 USETW(req.wValue, wVal);
387 USETW(req.wIndex, reg);
388 USETW(req.wLength, 0);
389
390 if (usbd_do_request(sc->sc_udev, &req, NULL))
391 return (EIO);
392
393 return (0);
394 }
395
396 int
umcs_set_baudrate(struct umcs_softc * sc,uint8_t portno,uint32_t rate)397 umcs_set_baudrate(struct umcs_softc *sc, uint8_t portno, uint32_t rate)
398 {
399 int pn = sc->sc_subdevs[portno].pn;
400 int spreg = umcs_reg_sp(pn);
401 uint8_t lcr = sc->sc_subdevs[portno].lcr;
402 uint8_t clk, data;
403 uint16_t div;
404
405 if (umcs_calc_baudrate(rate, &div, &clk))
406 return (EINVAL);
407
408 DPRINTF("%s: portno %d set speed: %d (%02x/%d)\n", DEVNAME(sc), portno,
409 rate, clk, div);
410
411 /* Set clock source for standard BAUD frequencies */
412 if (umcs_get_reg(sc, spreg, &data))
413 return (EIO);
414 data &= UMCS_SPx_CLK_MASK;
415 if (umcs_set_reg(sc, spreg, data | clk))
416 return (EIO);
417
418 /* Set divider */
419 lcr |= UMCS_LCR_DIVISORS;
420 if (umcs_set_uart_reg(sc, portno, UMCS_REG_LCR, lcr))
421 return (EIO);
422 sc->sc_subdevs[portno].lcr = lcr;
423
424 if (umcs_set_uart_reg(sc, portno, UMCS_REG_DLL, div & 0xff) ||
425 umcs_set_uart_reg(sc, portno, UMCS_REG_DLM, (div >> 8) & 0xff))
426 return (EIO);
427
428 /* Turn off access to DLL/DLM registers of UART */
429 lcr &= ~UMCS_LCR_DIVISORS;
430 if (umcs_set_uart_reg(sc, portno, UMCS_REG_LCR, lcr))
431 return (EIO);
432 sc->sc_subdevs[portno].lcr = lcr;
433
434 return (0);
435 }
436
437 /* Maximum speeds for standard frequencies, when PLL is not used */
438 static const uint32_t umcs_baudrate_divisors[] = {
439 0, 115200, 230400, 403200, 460800, 806400, 921600, 1572864, 3145728,
440 };
441
442 int
umcs_calc_baudrate(uint32_t rate,uint16_t * divisor,uint8_t * clk)443 umcs_calc_baudrate(uint32_t rate, uint16_t *divisor, uint8_t *clk)
444 {
445 const uint8_t divisors_len = nitems(umcs_baudrate_divisors);
446 uint8_t i = 0;
447
448 if (rate > umcs_baudrate_divisors[divisors_len - 1])
449 return (-1);
450
451 for (i = 0; i < divisors_len - 1; i++) {
452 if (rate > umcs_baudrate_divisors[i] &&
453 rate <= umcs_baudrate_divisors[i + 1]) {
454 *divisor = umcs_baudrate_divisors[i + 1] / rate;
455 /* 0x00 .. 0x70 */
456 *clk = i << UMCS_SPx_CLK_SHIFT;
457 return (0);
458 }
459 }
460
461 return (-1);
462 }
463
464 int
umcs_detach(struct device * self,int flags)465 umcs_detach(struct device *self, int flags)
466 {
467 struct umcs_softc *sc = (struct umcs_softc *)self;
468
469 task_del(systq, &sc->sc_status_task);
470
471 if (sc->sc_ipipe != NULL) {
472 usbd_close_pipe(sc->sc_ipipe);
473 sc->sc_ipipe = NULL;
474 }
475
476 if (sc->sc_ibuf != NULL) {
477 free(sc->sc_ibuf, M_USBDEV, sc->sc_isize);
478 sc->sc_ibuf = NULL;
479 }
480
481 return (config_detach_children(self, flags));
482 }
483
484 void
umcs_get_status(void * self,int portno,uint8_t * lsr,uint8_t * msr)485 umcs_get_status(void *self, int portno, uint8_t *lsr, uint8_t *msr)
486 {
487 struct umcs_softc *sc = self;
488 uint8_t hw_lsr = 0; /* local line status register */
489 uint8_t hw_msr = 0; /* local modem status register */
490
491 if (usbd_is_dying(sc->sc_udev))
492 return;
493
494 /* Read LSR & MSR */
495 if (umcs_get_uart_reg(sc, portno, UMCS_REG_LSR, &hw_lsr) ||
496 umcs_get_uart_reg(sc, portno, UMCS_REG_MSR, &hw_msr))
497 return;
498
499 *lsr = hw_lsr;
500 *msr = hw_msr;
501 }
502
503 void
umcs_set(void * self,int portno,int reg,int onoff)504 umcs_set(void *self, int portno, int reg, int onoff)
505 {
506 struct umcs_softc *sc = self;
507
508 if (usbd_is_dying(sc->sc_udev))
509 return;
510
511 switch (reg) {
512 case UCOM_SET_DTR:
513 umcs_dtr(sc, portno, onoff);
514 break;
515 case UCOM_SET_RTS:
516 umcs_rts(sc, portno, onoff);
517 break;
518 case UCOM_SET_BREAK:
519 umcs_break(sc, portno, onoff);
520 break;
521 default:
522 break;
523 }
524 }
525
526 int
umcs_param(void * self,int portno,struct termios * t)527 umcs_param(void *self, int portno, struct termios *t)
528 {
529 struct umcs_softc *sc = self;
530 uint8_t lcr = sc->sc_subdevs[portno].lcr;
531 uint8_t mcr = sc->sc_subdevs[portno].mcr;
532 int error = 0;
533
534 if (t->c_cflag & CSTOPB)
535 lcr |= UMCS_LCR_STOPB2;
536 else
537 lcr |= UMCS_LCR_STOPB1;
538
539 lcr &= ~UMCS_LCR_PARITYMASK;
540 if (t->c_cflag & PARENB) {
541 lcr |= UMCS_LCR_PARITYON;
542 if (t->c_cflag & PARODD) {
543 lcr |= UMCS_LCR_PARITYODD;
544 } else {
545 lcr |= UMCS_LCR_PARITYEVEN;
546 }
547 } else {
548 lcr &= ~UMCS_LCR_PARITYON;
549 }
550
551 lcr &= ~UMCS_LCR_DATALENMASK;
552 switch (t->c_cflag & CSIZE) {
553 case CS5:
554 lcr |= UMCS_LCR_DATALEN5;
555 break;
556 case CS6:
557 lcr |= UMCS_LCR_DATALEN6;
558 break;
559 case CS7:
560 lcr |= UMCS_LCR_DATALEN7;
561 break;
562 case CS8:
563 lcr |= UMCS_LCR_DATALEN8;
564 break;
565 }
566
567 if (t->c_cflag & CRTSCTS)
568 mcr |= UMCS_MCR_CTSRTS;
569 else
570 mcr &= ~UMCS_MCR_CTSRTS;
571
572 if (t->c_cflag & CLOCAL)
573 mcr &= ~UMCS_MCR_DTRDSR;
574 else
575 mcr |= UMCS_MCR_DTRDSR;
576
577 if (umcs_set_uart_reg(sc, portno, UMCS_REG_LCR, lcr))
578 return (EIO);
579 sc->sc_subdevs[portno].lcr = lcr;
580
581 if (umcs_set_uart_reg(sc, portno, UMCS_REG_MCR, mcr))
582 return (EIO);
583 sc->sc_subdevs[portno].mcr = mcr;
584
585 error = umcs_set_baudrate(sc, portno, t->c_ospeed);
586
587 return (error);
588 }
589
590 void
umcs_dtr(struct umcs_softc * sc,int portno,int onoff)591 umcs_dtr(struct umcs_softc *sc, int portno, int onoff)
592 {
593 uint8_t mcr = sc->sc_subdevs[portno].mcr;
594
595 if (onoff)
596 mcr |= UMCS_MCR_DTR;
597 else
598 mcr &= ~UMCS_MCR_DTR;
599
600 if (umcs_set_uart_reg(sc, portno, UMCS_REG_MCR, mcr))
601 return;
602 sc->sc_subdevs[portno].mcr = mcr;
603 }
604
605 void
umcs_rts(struct umcs_softc * sc,int portno,int onoff)606 umcs_rts(struct umcs_softc *sc, int portno, int onoff)
607 {
608 uint8_t mcr = sc->sc_subdevs[portno].mcr;
609
610 if (onoff)
611 mcr |= UMCS_MCR_RTS;
612 else
613 mcr &= ~UMCS_MCR_RTS;
614
615 if (umcs_set_uart_reg(sc, portno, UMCS_REG_MCR, mcr))
616 return;
617 sc->sc_subdevs[portno].mcr = mcr;
618 }
619
620 void
umcs_break(struct umcs_softc * sc,int portno,int onoff)621 umcs_break(struct umcs_softc *sc, int portno, int onoff)
622 {
623 uint8_t lcr = sc->sc_subdevs[portno].lcr;
624
625 if (onoff)
626 lcr |= UMCS_LCR_BREAK;
627 else
628 lcr &= ~UMCS_LCR_BREAK;
629
630 if (umcs_set_uart_reg(sc, portno, UMCS_REG_LCR, lcr))
631 return;
632 sc->sc_subdevs[portno].lcr = lcr;
633 }
634
635 int
umcs_open(void * self,int portno)636 umcs_open(void *self, int portno)
637 {
638 struct umcs_softc *sc = self;
639 int pn = sc->sc_subdevs[portno].pn;
640 int spreg = umcs_reg_sp(pn);
641 int ctrlreg = umcs_reg_ctrl(pn);
642 uint8_t mcr = sc->sc_subdevs[portno].mcr;
643 uint8_t lcr = sc->sc_subdevs[portno].lcr;
644 uint8_t data;
645 int error;
646
647 if (usbd_is_dying(sc->sc_udev))
648 return (EIO);
649
650 /* If it very first open, finish global configuration */
651 if (!sc->sc_init_done) {
652 if (umcs_get_reg(sc, UMCS_CTRL1, &data) ||
653 umcs_set_reg(sc, UMCS_CTRL1, data | UMCS_CTRL1_DRIVER_DONE))
654 return (EIO);
655 sc->sc_init_done = 1;
656 }
657
658 /* Toggle reset bit on-off */
659 if (umcs_get_reg(sc, spreg, &data) ||
660 umcs_set_reg(sc, spreg, data | UMCS_SPx_UART_RESET) ||
661 umcs_set_reg(sc, spreg, data & ~UMCS_SPx_UART_RESET))
662 return (EIO);
663
664 /* Set RS-232 mode */
665 if (umcs_set_uart_reg(sc, portno, UMCS_REG_SCRATCHPAD,
666 UMCS_SCRATCHPAD_RS232))
667 return (EIO);
668
669 /* Disable RX on time of initialization */
670 if (umcs_get_reg(sc, ctrlreg, &data) ||
671 umcs_set_reg(sc, ctrlreg, data | UMCS_CTRL_RX_DISABLE))
672 return (EIO);
673
674 /* Disable all interrupts */
675 if (umcs_set_uart_reg(sc, portno, UMCS_REG_IER, 0))
676 return (EIO);
677
678 /* Reset FIFO -- documented */
679 if (umcs_set_uart_reg(sc, portno, UMCS_REG_FCR, 0) ||
680 umcs_set_uart_reg(sc, portno, UMCS_REG_FCR,
681 UMCS_FCR_ENABLE | UMCS_FCR_FLUSHRHR |
682 UMCS_FCR_FLUSHTHR | UMCS_FCR_RTL_1_14))
683 return (EIO);
684
685 /* Set 8 bit, no parity, 1 stop bit -- documented */
686 lcr = UMCS_LCR_DATALEN8 | UMCS_LCR_STOPB1;
687 if (umcs_set_uart_reg(sc, portno, UMCS_REG_LCR, lcr))
688 return (EIO);
689 sc->sc_subdevs[portno].lcr = lcr;
690
691 /*
692 * Enable DTR/RTS on modem control, enable modem interrupts --
693 * documented
694 */
695 mcr = UMCS_MCR_DTR | UMCS_MCR_RTS | UMCS_MCR_IE;
696 if (umcs_set_uart_reg(sc, portno, UMCS_REG_MCR, mcr))
697 return (EIO);
698 sc->sc_subdevs[portno].mcr = mcr;
699
700 /* Clearing Bulkin and Bulkout FIFO */
701 if (umcs_get_reg(sc, spreg, &data))
702 return (EIO);
703 data |= UMCS_SPx_RESET_OUT_FIFO|UMCS_SPx_RESET_IN_FIFO;
704 if (umcs_set_reg(sc, spreg, data))
705 return (EIO);
706 data &= ~(UMCS_SPx_RESET_OUT_FIFO|UMCS_SPx_RESET_IN_FIFO);
707 if (umcs_set_reg(sc, spreg, data))
708 return (EIO);
709
710 /* Set speed 9600 */
711 if ((error = umcs_set_baudrate(sc, portno, 9600)) != 0)
712 return (error);
713
714 /* Finally enable all interrupts -- documented */
715 /*
716 * Copied from vendor driver, I don't know why we should read LCR
717 * here
718 */
719 if (umcs_get_uart_reg(sc, portno, UMCS_REG_LCR,
720 &sc->sc_subdevs[portno].lcr))
721 return (EIO);
722 if (umcs_set_uart_reg(sc, portno, UMCS_REG_IER,
723 UMCS_IER_RXSTAT | UMCS_IER_MODEM))
724 return (EIO);
725
726 /* Enable RX */
727 if (umcs_get_reg(sc, ctrlreg, &data) ||
728 umcs_set_reg(sc, ctrlreg, data & ~UMCS_CTRL_RX_DISABLE))
729 return (EIO);
730
731 return (0);
732 }
733
734 void
umcs_close(void * self,int portno)735 umcs_close(void *self, int portno)
736 {
737 struct umcs_softc *sc = self;
738 int pn = sc->sc_subdevs[portno].pn;
739 int ctrlreg = umcs_reg_ctrl(pn);
740 uint8_t data;
741
742 if (usbd_is_dying(sc->sc_udev))
743 return;
744
745 umcs_set_uart_reg(sc, portno, UMCS_REG_MCR, 0);
746 umcs_set_uart_reg(sc, portno, UMCS_REG_IER, 0);
747
748 /* Disable RX */
749 if (umcs_get_reg(sc, ctrlreg, &data) ||
750 umcs_set_reg(sc, ctrlreg, data | UMCS_CTRL_RX_DISABLE))
751 return;
752 }
753
754 void
umcs_intr(struct usbd_xfer * xfer,void * priv,usbd_status status)755 umcs_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
756 {
757 struct umcs_softc *sc = priv;
758 uint8_t *buf = sc->sc_ibuf;
759 int actlen, i;
760
761 if (usbd_is_dying(sc->sc_udev))
762 return;
763
764 if (status == USBD_CANCELLED || status == USBD_IOERROR)
765 return;
766
767 if (status != USBD_NORMAL_COMPLETION) {
768 DPRINTF("%s: interrupt status=%d\n", DEVNAME(sc), status);
769 usbd_clear_endpoint_stall_async(sc->sc_ipipe);
770 return;
771 }
772
773 usbd_get_xfer_status(xfer, NULL, NULL, &actlen, NULL);
774 if (actlen != 5 && actlen != 13) {
775 printf("%s: invalid interrupt data length %d\n", DEVNAME(sc),
776 actlen);
777 return;
778 }
779
780 /* Check status of all ports */
781 for (i = 0; i < sc->sc_numports; i++) {
782 uint8_t pn = sc->sc_subdevs[i].pn;
783
784 if (buf[pn] & UMCS_ISR_NOPENDING)
785 continue;
786
787 DPRINTF("%s: port %d has pending interrupt: %02x, FIFO=%02x\n",
788 DEVNAME(sc), i, buf[pn] & UMCS_ISR_INTMASK,
789 buf[pn] & (~UMCS_ISR_INTMASK));
790
791 switch (buf[pn] & UMCS_ISR_INTMASK) {
792 case UMCS_ISR_RXERR:
793 case UMCS_ISR_RXHASDATA:
794 case UMCS_ISR_RXTIMEOUT:
795 case UMCS_ISR_MSCHANGE:
796 sc->sc_subdevs[i].flags |= UMCS_STATCHG;
797 task_add(systq, &sc->sc_status_task);
798 break;
799 default:
800 /* Do nothing */
801 break;
802 }
803 }
804 }
805
806 void
umcs_status_task(void * arg)807 umcs_status_task(void *arg)
808 {
809 struct umcs_softc *sc = arg;
810 int i;
811
812 for (i = 0; i < sc->sc_numports; i++) {
813 if ((sc->sc_subdevs[i].flags & UMCS_STATCHG) == 0)
814 continue;
815
816 sc->sc_subdevs[i].flags &= ~UMCS_STATCHG;
817 ucom_status_change(sc->sc_subdevs[i].ucom);
818 }
819 }
820