]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - sys/dev/usb/serial/umcs.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / sys / dev / usb / serial / umcs.c
1 /*-
2  * Copyright (c) 2010 Lev Serebryakov <lev@FreeBSD.org>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28  * This driver supports several multiport USB-to-RS232 serial adapters driven
29  * by MosChip mos7820 and mos7840, bridge chips.
30  * The adapters are sold under many different brand names.
31  *
32  * Datasheets are available at MosChip www site at
33  * http://www.moschip.com.  The datasheets don't contain full
34  * programming information for the chip.
35  *
36  * It is nornal to have only two enabled ports in devices, based on
37  * quad-port mos7840.
38  *
39  */
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include <sys/stdint.h>
44 #include <sys/stddef.h>
45 #include <sys/param.h>
46 #include <sys/queue.h>
47 #include <sys/types.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/bus.h>
51 #include <sys/linker_set.h>
52 #include <sys/module.h>
53 #include <sys/lock.h>
54 #include <sys/mutex.h>
55 #include <sys/condvar.h>
56 #include <sys/sysctl.h>
57 #include <sys/sx.h>
58 #include <sys/unistd.h>
59 #include <sys/callout.h>
60 #include <sys/malloc.h>
61 #include <sys/priv.h>
62
63 #include <dev/usb/usb.h>
64 #include <dev/usb/usbdi.h>
65 #include <dev/usb/usbdi_util.h>
66 #include <dev/usb/usb_cdc.h>
67 #include "usbdevs.h"
68
69 #define USB_DEBUG_VAR umcs_debug
70 #include <dev/usb/usb_debug.h>
71 #include <dev/usb/usb_process.h>
72
73 #include <dev/usb/serial/usb_serial.h>
74
75 #include <dev/usb/serial/umcs.h>
76
77 #define UMCS7840_MODVER 1
78
79 #ifdef USB_DEBUG
80 static int umcs_debug = 0;
81
82 SYSCTL_NODE(_hw_usb, OID_AUTO, umcs, CTLFLAG_RW, 0, "USB umcs quadport serial adapter");
83 SYSCTL_INT(_hw_usb_umcs, OID_AUTO, debug, CTLFLAG_RW, &umcs_debug, 0, "Debug level");
84 #endif                                  /* USB_DEBUG */
85
86
87 /*
88  * Two-port devices (both with 7820 chip and 7840 chip configured as two-port)
89  * have ports 0 and 2, with ports 1 and 3 omitted.
90  * So,PHYSICAL port numbers (indexes) on two-port device will be 0 and 2.
91  * This driver trys to use physical numbers as much as possible.
92  */
93
94 /*
95  * Indexed by PHYSICAL port number.
96  * Pack non-regular registers to array to easier if-less access.
97  */
98 struct umcs7840_port_registers {
99         uint8_t reg_sp;                 /* SP register. */
100         uint8_t reg_control;            /* CONTROL register. */
101         uint8_t reg_dcr;                /* DCR0 register. DCR1 & DCR2 can be
102                                          * calculated */
103 };
104
105 static const struct umcs7840_port_registers umcs7840_port_registers[UMCS7840_MAX_PORTS] = {
106         {.reg_sp = MCS7840_DEV_REG_SP1,.reg_control = MCS7840_DEV_REG_CONTROL1,.reg_dcr = MCS7840_DEV_REG_DCR0_1},
107         {.reg_sp = MCS7840_DEV_REG_SP2,.reg_control = MCS7840_DEV_REG_CONTROL2,.reg_dcr = MCS7840_DEV_REG_DCR0_2},
108         {.reg_sp = MCS7840_DEV_REG_SP3,.reg_control = MCS7840_DEV_REG_CONTROL3,.reg_dcr = MCS7840_DEV_REG_DCR0_3},
109         {.reg_sp = MCS7840_DEV_REG_SP4,.reg_control = MCS7840_DEV_REG_CONTROL4,.reg_dcr = MCS7840_DEV_REG_DCR0_4},
110 };
111
112 enum {
113         UMCS7840_BULK_RD_EP,
114         UMCS7840_BULK_WR_EP,
115         UMCS7840_N_TRANSFERS
116 };
117
118 struct umcs7840_softc_oneport {
119         struct usb_xfer *sc_xfer[UMCS7840_N_TRANSFERS]; /* Control structures
120                                                          * for two transfers */
121
122         uint8_t sc_lcr;                 /* local line control register */
123         uint8_t sc_mcr;                 /* local modem control register */
124         uint8_t sc_lsr;                 /* local line status register */
125         uint8_t sc_msr;                 /* local modem status register */
126 };
127
128 struct umcs7840_softc {
129         struct ucom_super_softc sc_super_ucom;
130         struct ucom_softc sc_ucom[UMCS7840_MAX_PORTS];  /* Need to be continuous
131                                                          * array, so indexed by
132                                                          * LOGICAL port
133                                                          * (subunit) number */
134
135         struct usb_xfer *sc_intr_xfer;  /* Interrupt endpoint */
136
137         device_t sc_dev;                /* Device for error prints */
138         struct usb_device *sc_udev;     /* USB Device for all operations */
139         struct mtx sc_mtx;              /* ucom requires this */
140
141         uint8_t sc_driver_done;         /* Flag when enumeration is finished */
142
143         uint8_t sc_numports;            /* Number of ports (subunits) */
144         struct umcs7840_softc_oneport sc_ports[UMCS7840_MAX_PORTS];     /* Indexed by PHYSICAL
145                                                                          * port number. */
146 };
147
148 /* prototypes */
149 static usb_error_t umcs7840_get_reg_sync(struct umcs7840_softc *, uint8_t, uint8_t *);
150 static usb_error_t umcs7840_set_reg_sync(struct umcs7840_softc *, uint8_t, uint8_t);
151 static usb_error_t umcs7840_get_UART_reg_sync(struct umcs7840_softc *, uint8_t, uint8_t, uint8_t *);
152 static usb_error_t umcs7840_set_UART_reg_sync(struct umcs7840_softc *, uint8_t, uint8_t, uint8_t);
153
154 static usb_error_t umcs7840_set_baudrate(struct umcs7840_softc *, uint8_t, uint32_t);
155 static usb_error_t umcs7840_calc_baudrate(uint32_t rate, uint16_t *, uint8_t *);
156
157 static void umcs7840_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *);
158 static void umcs7840_cfg_set_dtr(struct ucom_softc *, uint8_t);
159 static void umcs7840_cfg_set_rts(struct ucom_softc *, uint8_t);
160 static void umcs7840_cfg_set_break(struct ucom_softc *, uint8_t);
161 static void umcs7840_cfg_param(struct ucom_softc *, struct termios *);
162 static void umcs7840_cfg_open(struct ucom_softc *);
163 static void umcs7840_cfg_close(struct ucom_softc *);
164
165 static int umcs7840_pre_param(struct ucom_softc *, struct termios *);
166
167 static void umcs7840_start_read(struct ucom_softc *);
168 static void umcs7840_stop_read(struct ucom_softc *);
169
170 static void umcs7840_start_write(struct ucom_softc *);
171 static void umcs7840_stop_write(struct ucom_softc *);
172
173 static void umcs7840_poll(struct ucom_softc *ucom);
174
175 static device_probe_t umcs7840_probe;
176 static device_attach_t umcs7840_attach;
177 static device_detach_t umcs7840_detach;
178
179 static usb_callback_t umcs7840_intr_callback;
180 static usb_callback_t umcs7840_read_callback1;
181 static usb_callback_t umcs7840_read_callback2;
182 static usb_callback_t umcs7840_read_callback3;
183 static usb_callback_t umcs7840_read_callback4;
184 static usb_callback_t umcs7840_write_callback1;
185 static usb_callback_t umcs7840_write_callback2;
186 static usb_callback_t umcs7840_write_callback3;
187 static usb_callback_t umcs7840_write_callback4;
188
189 static void umcs7840_read_callbackN(struct usb_xfer *, usb_error_t, uint8_t);
190 static void umcs7840_write_callbackN(struct usb_xfer *, usb_error_t, uint8_t);
191
192 /* Indexed by LOGICAL port number (subunit), so two-port device uses 0 & 1 */
193 static usb_callback_t *umcs7840_rw_callbacks[UMCS7840_MAX_PORTS][UMCS7840_N_TRANSFERS] = {
194         {&umcs7840_read_callback1, &umcs7840_write_callback1},
195         {&umcs7840_read_callback2, &umcs7840_write_callback2},
196         {&umcs7840_read_callback3, &umcs7840_write_callback3},
197         {&umcs7840_read_callback4, &umcs7840_write_callback4},
198 };
199
200 static const struct usb_config umcs7840_bulk_config_data[UMCS7840_N_TRANSFERS] = {
201         [UMCS7840_BULK_RD_EP] = {
202                 .type = UE_BULK,
203                 .endpoint = 0x01,
204                 .direction = UE_DIR_IN,
205                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
206                 .bufsize = 0,           /* use wMaxPacketSize */
207                 .callback = &umcs7840_read_callback1,
208                 .if_index = 0,
209         },
210
211         [UMCS7840_BULK_WR_EP] = {
212                 .type = UE_BULK,
213                 .endpoint = 0x02,
214                 .direction = UE_DIR_OUT,
215                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
216                 .bufsize = 0,           /* use wMaxPacketSize */
217                 .callback = &umcs7840_write_callback1,
218                 .if_index = 0,
219         },
220 };
221
222 static const struct usb_config umcs7840_intr_config_data[1] = {
223         [0] = {
224                 .type = UE_INTERRUPT,
225                 .endpoint = 0x09,
226                 .direction = UE_DIR_IN,
227                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
228                 .bufsize = 0,           /* use wMaxPacketSize */
229                 .callback = &umcs7840_intr_callback,
230                 .if_index = 0,
231         },
232 };
233
234 static struct ucom_callback umcs7840_callback = {
235         .ucom_cfg_get_status = &umcs7840_cfg_get_status,
236
237         .ucom_cfg_set_dtr = &umcs7840_cfg_set_dtr,
238         .ucom_cfg_set_rts = &umcs7840_cfg_set_rts,
239         .ucom_cfg_set_break = &umcs7840_cfg_set_break,
240
241         .ucom_cfg_param = &umcs7840_cfg_param,
242         .ucom_cfg_open = &umcs7840_cfg_open,
243         .ucom_cfg_close = &umcs7840_cfg_close,
244
245         .ucom_pre_param = &umcs7840_pre_param,
246
247         .ucom_start_read = &umcs7840_start_read,
248         .ucom_stop_read = &umcs7840_stop_read,
249
250         .ucom_start_write = &umcs7840_start_write,
251         .ucom_stop_write = &umcs7840_stop_write,
252
253         .ucom_poll = &umcs7840_poll,
254 };
255
256 static const STRUCT_USB_HOST_ID umcs7840_devs[] = {
257         {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7820, 0)},
258         {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7840, 0)},
259 };
260
261 static device_method_t umcs7840_methods[] = {
262         DEVMETHOD(device_probe, umcs7840_probe),
263         DEVMETHOD(device_attach, umcs7840_attach),
264         DEVMETHOD(device_detach, umcs7840_detach),
265         {0, 0}
266 };
267
268 static devclass_t umcs7840_devclass;
269
270 static driver_t umcs7840_driver = {
271         .name = "umcs7840",
272         .methods = umcs7840_methods,
273         .size = sizeof(struct umcs7840_softc),
274 };
275
276 DRIVER_MODULE(umcs7840, uhub, umcs7840_driver, umcs7840_devclass, 0, 0);
277 MODULE_DEPEND(umcs7840, ucom, 1, 1, 1);
278 MODULE_DEPEND(umcs7840, usb, 1, 1, 1);
279 MODULE_VERSION(umcs7840, UMCS7840_MODVER);
280
281 static int
282 umcs7840_probe(device_t dev)
283 {
284         struct usb_attach_arg *uaa = device_get_ivars(dev);
285
286         if (uaa->usb_mode != USB_MODE_HOST)
287                 return (ENXIO);
288         if (uaa->info.bConfigIndex != MCS7840_CONFIG_INDEX)
289                 return (ENXIO);
290         if (uaa->info.bIfaceIndex != MCS7840_IFACE_INDEX)
291                 return (ENXIO);
292         return (usbd_lookup_id_by_uaa(umcs7840_devs, sizeof(umcs7840_devs), uaa));
293 }
294
295 static int
296 umcs7840_attach(device_t dev)
297 {
298         struct usb_config umcs7840_config_tmp[UMCS7840_N_TRANSFERS];
299         struct usb_attach_arg *uaa = device_get_ivars(dev);
300         struct umcs7840_softc *sc = device_get_softc(dev);
301
302         uint8_t iface_index = MCS7840_IFACE_INDEX;
303         int error;
304         int subunit;
305         int n;
306         uint8_t data;
307
308         for (n = 0; n < UMCS7840_N_TRANSFERS; ++n)
309                 umcs7840_config_tmp[n] = umcs7840_bulk_config_data[n];
310
311         device_set_usb_desc(dev);
312         mtx_init(&sc->sc_mtx, "umcs7840", NULL, MTX_DEF);
313
314         sc->sc_dev = dev;
315         sc->sc_udev = uaa->device;
316
317         /*
318          * Get number of ports
319          * Documentation (full datasheet) says, that number of ports is
320          * set as MCS7840_DEV_MODE_SELECT24S bit in MODE R/Only
321          * register. But vendor driver uses these undocumented
322          * register & bit.
323          *
324          * Experiments show, that MODE register can have `0'
325          * (4 ports) bit on 2-port device, so use vendor driver's way.
326          *
327          * Also, see notes in header file for these constants.
328          */
329         umcs7840_get_reg_sync(sc, MCS7840_DEV_REG_GPIO, &data);
330         if (data & MCS7840_DEV_GPIO_4PORTS) {
331                 sc->sc_numports = 4;
332                 /* Store physical port numbers in sc_portno */
333                 sc->sc_ucom[0].sc_portno = 0;
334                 sc->sc_ucom[1].sc_portno = 1;
335                 sc->sc_ucom[2].sc_portno = 2;
336                 sc->sc_ucom[3].sc_portno = 3;
337         } else {
338                 sc->sc_numports = 2;
339                 /* Store physical port numbers in sc_portno */
340                 sc->sc_ucom[0].sc_portno = 0;
341                 sc->sc_ucom[1].sc_portno = 2;   /* '1' is skipped */
342         }
343         device_printf(dev, "Chip mcs%04x, found %d active ports\n", uaa->info.idProduct, sc->sc_numports);
344         if (!umcs7840_get_reg_sync(sc, MCS7840_DEV_REG_MODE, &data)) {
345                 device_printf(dev, "On-die confguration: RST: active %s, HRD: %s, PLL: %s, POR: %s, Ports: %s, EEPROM write %s, IrDA is %savailable\n",
346                     (data & MCS7840_DEV_MODE_RESET) ? "low" : "high",
347                     (data & MCS7840_DEV_MODE_SER_PRSNT) ? "yes" : "no",
348                     (data & MCS7840_DEV_MODE_PLLBYPASS) ? "bypassed" : "avail",
349                     (data & MCS7840_DEV_MODE_PORBYPASS) ? "bypassed" : "avail",
350                     (data & MCS7840_DEV_MODE_SELECT24S) ? "2" : "4",
351                     (data & MCS7840_DEV_MODE_EEPROMWR) ? "enabled" : "disabled",
352                     (data & MCS7840_DEV_MODE_IRDA) ? "" : "not ");
353         }
354         /* Setup all transfers */
355         for (subunit = 0; subunit < sc->sc_numports; ++subunit) {
356                 for (n = 0; n < UMCS7840_N_TRANSFERS; ++n) {
357                         /* Set endpoint address */
358                         umcs7840_config_tmp[n].endpoint = umcs7840_bulk_config_data[n].endpoint + 2 * sc->sc_ucom[subunit].sc_portno;
359                         umcs7840_config_tmp[n].callback = umcs7840_rw_callbacks[subunit][n];
360                 }
361                 error = usbd_transfer_setup(uaa->device,
362                     &iface_index, sc->sc_ports[sc->sc_ucom[subunit].sc_portno].sc_xfer, umcs7840_config_tmp,
363                     UMCS7840_N_TRANSFERS, sc, &sc->sc_mtx);
364                 if (error) {
365                         device_printf(dev, "allocating USB transfers failed for subunit %d of %d\n",
366                             subunit + 1, sc->sc_numports);
367                         goto detach;
368                 }
369         }
370         error = usbd_transfer_setup(uaa->device,
371             &iface_index, &sc->sc_intr_xfer, umcs7840_intr_config_data,
372             1, sc, &sc->sc_mtx);
373         if (error) {
374                 device_printf(dev, "allocating USB transfers failed for interrupt\n");
375                 goto detach;
376         }
377         /* clear stall at first run */
378         mtx_lock(&sc->sc_mtx);
379         for (subunit = 0; subunit < sc->sc_numports; ++subunit) {
380                 usbd_xfer_set_stall(sc->sc_ports[sc->sc_ucom[subunit].sc_portno].sc_xfer[UMCS7840_BULK_RD_EP]);
381                 usbd_xfer_set_stall(sc->sc_ports[sc->sc_ucom[subunit].sc_portno].sc_xfer[UMCS7840_BULK_WR_EP]);
382         }
383         mtx_unlock(&sc->sc_mtx);
384
385         error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_numports, sc,
386             &umcs7840_callback, &sc->sc_mtx);
387         if (error)
388                 goto detach;
389
390         ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
391
392         return (0);
393
394 detach:
395         umcs7840_detach(dev);
396         return (ENXIO);
397 }
398
399 static int
400 umcs7840_detach(device_t dev)
401 {
402         struct umcs7840_softc *sc = device_get_softc(dev);
403         int subunit;
404
405         ucom_detach(&sc->sc_super_ucom, sc->sc_ucom);
406
407         for (subunit = 0; subunit < sc->sc_numports; ++subunit)
408                 usbd_transfer_unsetup(sc->sc_ports[sc->sc_ucom[subunit].sc_portno].sc_xfer, UMCS7840_N_TRANSFERS);
409         usbd_transfer_unsetup(&sc->sc_intr_xfer, 1);
410
411         mtx_destroy(&sc->sc_mtx);
412         return (0);
413 }
414
415 static void
416 umcs7840_cfg_open(struct ucom_softc *ucom)
417 {
418         struct umcs7840_softc *sc = ucom->sc_parent;
419         uint16_t pn = ucom->sc_portno;
420         uint8_t data;
421
422         /* If it very first open, finish global configuration */
423         if (!sc->sc_driver_done) {
424                 /*
425                  * USB enumeration is finished, pass internal memory to FIFOs
426                  * If it is done in the end of "attach", kernel panics.
427                  */
428                 if (umcs7840_get_reg_sync(sc, MCS7840_DEV_REG_CONTROL1, &data))
429                         return;
430                 data |= MCS7840_DEV_CONTROL1_DRIVER_DONE;
431                 if (umcs7840_set_reg_sync(sc, MCS7840_DEV_REG_CONTROL1, data))
432                         return;
433                 sc->sc_driver_done = 1;
434         }
435         /* Toggle reset bit on-off */
436         if (umcs7840_get_reg_sync(sc, umcs7840_port_registers[pn].reg_sp, &data))
437                 return;
438         data |= MCS7840_DEV_SPx_UART_RESET;
439         if (umcs7840_set_reg_sync(sc, umcs7840_port_registers[pn].reg_sp, data))
440                 return;
441         data &= ~MCS7840_DEV_SPx_UART_RESET;
442         if (umcs7840_set_reg_sync(sc, umcs7840_port_registers[pn].reg_sp, data))
443                 return;
444
445         /* Set RS-232 mode */
446         if (umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_SCRATCHPAD, MCS7840_UART_SCRATCHPAD_RS232))
447                 return;
448
449         /* Disable RX on time of initialization */
450         if (umcs7840_get_reg_sync(sc, umcs7840_port_registers[pn].reg_control, &data))
451                 return;
452         data |= MCS7840_DEV_CONTROLx_RX_DISABLE;
453         if (umcs7840_set_reg_sync(sc, umcs7840_port_registers[pn].reg_control, data))
454                 return;
455
456         /* Disable all interrupts */
457         if (umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_IER, 0))
458                 return;
459
460         /* Reset FIFO -- documented */
461         if (umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_FCR, 0))
462                 return;
463         if (umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_FCR,
464             MCS7840_UART_FCR_ENABLE | MCS7840_UART_FCR_FLUSHRHR |
465             MCS7840_UART_FCR_FLUSHTHR | MCS7840_UART_FCR_RTL_1_14))
466                 return;
467
468         /* Set 8 bit, no parity, 1 stop bit -- documented */
469         sc->sc_ports[pn].sc_lcr = MCS7840_UART_LCR_DATALEN8 | MCS7840_UART_LCR_STOPB1;
470         if (umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_LCR, sc->sc_ports[pn].sc_lcr))
471                 return;
472
473         /*
474          * Enable DTR/RTS on modem control, enable modem interrupts --
475          * documented
476          */
477         sc->sc_ports[pn].sc_mcr = MCS7840_UART_MCR_DTR | MCS7840_UART_MCR_RTS | MCS7840_UART_MCR_IE;
478         if (umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_MCR, sc->sc_ports[pn].sc_mcr))
479                 return;
480
481         /* Clearing Bulkin and Bulkout FIFO */
482         if (umcs7840_get_reg_sync(sc, umcs7840_port_registers[pn].reg_sp, &data))
483                 return;
484         data |= MCS7840_DEV_SPx_RESET_OUT_FIFO | MCS7840_DEV_SPx_RESET_IN_FIFO;
485         if (umcs7840_set_reg_sync(sc, umcs7840_port_registers[pn].reg_sp, data))
486                 return;
487         data &= ~(MCS7840_DEV_SPx_RESET_OUT_FIFO | MCS7840_DEV_SPx_RESET_IN_FIFO);
488         if (umcs7840_set_reg_sync(sc, umcs7840_port_registers[pn].reg_sp, data))
489                 return;
490
491         /* Set speed 9600 */
492         if (umcs7840_set_baudrate(sc, pn, 9600))
493                 return;
494
495
496         /* Finally enable all interrupts -- documented */
497         /*
498          * Copied from vendor driver, I don't know why we should read LCR
499          * here
500          */
501         if (umcs7840_get_UART_reg_sync(sc, pn, MCS7840_UART_REG_LCR, &sc->sc_ports[pn].sc_lcr))
502                 return;
503         if (umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_IER,
504             MCS7840_UART_IER_RXSTAT | MCS7840_UART_IER_MODEM))
505                 return;
506
507         /* Enable RX */
508         if (umcs7840_get_reg_sync(sc, umcs7840_port_registers[pn].reg_control, &data))
509                 return;
510         data &= ~MCS7840_DEV_CONTROLx_RX_DISABLE;
511         if (umcs7840_set_reg_sync(sc, umcs7840_port_registers[pn].reg_control, data))
512                 return;
513
514         /* Read LSR & MSR */
515         if (umcs7840_get_UART_reg_sync(sc, pn, MCS7840_UART_REG_LSR, &sc->sc_ports[pn].sc_lsr))
516                 return;
517         if (umcs7840_get_UART_reg_sync(sc, pn, MCS7840_UART_REG_MSR, &sc->sc_ports[pn].sc_msr))
518                 return;
519         DPRINTF("Port %d has been opened, LSR=%02x MSR=%02x\n", pn, sc->sc_ports[pn].sc_lsr, sc->sc_ports[pn].sc_msr);
520 }
521
522 static void
523 umcs7840_cfg_close(struct ucom_softc *ucom)
524 {
525         struct umcs7840_softc *sc = ucom->sc_parent;
526         uint16_t pn = ucom->sc_portno;
527         uint8_t data;
528
529         umcs7840_stop_read(ucom);
530         umcs7840_stop_write(ucom);
531
532         umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_MCR, 0);
533         umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_IER, 0);
534
535         /* Disable RX */
536         if (umcs7840_get_reg_sync(sc, umcs7840_port_registers[pn].reg_control, &data))
537                 return;
538         data |= MCS7840_DEV_CONTROLx_RX_DISABLE;
539         if (umcs7840_set_reg_sync(sc, umcs7840_port_registers[pn].reg_control, data))
540                 return;
541         DPRINTF("Port %d has been closed\n", pn);
542 }
543
544 static void
545 umcs7840_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
546 {
547         struct umcs7840_softc *sc = ucom->sc_parent;
548         uint8_t pn = ucom->sc_portno;
549
550         if (onoff)
551                 sc->sc_ports[pn].sc_mcr |= MCS7840_UART_MCR_DTR;
552         else
553                 sc->sc_ports[pn].sc_mcr &= ~MCS7840_UART_MCR_DTR;
554
555         umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_MCR, sc->sc_ports[pn].sc_mcr);
556         DPRINTF("Port %d DTR set to: %s\n", pn, onoff ? "on" : "off");
557 }
558
559 static void
560 umcs7840_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
561 {
562         struct umcs7840_softc *sc = ucom->sc_parent;
563         uint8_t pn = ucom->sc_portno;
564
565         if (onoff)
566                 sc->sc_ports[pn].sc_mcr |= MCS7840_UART_MCR_RTS;
567         else
568                 sc->sc_ports[pn].sc_mcr &= ~MCS7840_UART_MCR_RTS;
569
570         umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_MCR, sc->sc_ports[pn].sc_mcr);
571         DPRINTF("Port %d RTS set to: %s\n", pn, onoff ? "on" : "off");
572 }
573
574 static void
575 umcs7840_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
576 {
577         struct umcs7840_softc *sc = ucom->sc_parent;
578         uint8_t pn = ucom->sc_portno;
579
580         if (onoff)
581                 sc->sc_ports[pn].sc_lcr |= MCS7840_UART_LCR_BREAK;
582         else
583                 sc->sc_ports[pn].sc_lcr &= ~MCS7840_UART_LCR_BREAK;
584
585         umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_LCR, sc->sc_ports[pn].sc_lcr);
586         DPRINTF("Port %d BREAK set to: %s\n", pn, onoff ? "on" : "off");
587 }
588
589
590 static void
591 umcs7840_cfg_param(struct ucom_softc *ucom, struct termios *t)
592 {
593         struct umcs7840_softc *sc = ucom->sc_parent;
594         uint8_t pn = ucom->sc_portno;
595         uint8_t lcr = sc->sc_ports[pn].sc_lcr;
596         uint8_t mcr = sc->sc_ports[pn].sc_mcr;
597
598         DPRINTF("Port %d config:\n", pn);
599         if (t->c_cflag & CSTOPB) {
600                 DPRINTF("  2 stop bits\n");
601                 lcr |= MCS7840_UART_LCR_STOPB2;
602         } else {
603                 lcr |= MCS7840_UART_LCR_STOPB1;
604                 DPRINTF("  1 stop bit\n");
605         }
606
607         lcr &= ~MCS7840_UART_LCR_PARITYMASK;
608         if (t->c_cflag & PARENB) {
609                 lcr |= MCS7840_UART_LCR_PARITYON;
610                 if (t->c_cflag & PARODD) {
611                         lcr = MCS7840_UART_LCR_PARITYODD;
612                         DPRINTF("  parity on - odd\n");
613                 } else {
614                         lcr = MCS7840_UART_LCR_PARITYEVEN;
615                         DPRINTF("  parity on - even\n");
616                 }
617         } else {
618                 lcr &= ~MCS7840_UART_LCR_PARITYON;
619                 DPRINTF("  parity off\n");
620         }
621
622         lcr &= ~MCS7840_UART_LCR_DATALENMASK;
623         switch (t->c_cflag & CSIZE) {
624         case CS5:
625                 lcr |= MCS7840_UART_LCR_DATALEN5;
626                 DPRINTF("  5 bit\n");
627                 break;
628         case CS6:
629                 lcr |= MCS7840_UART_LCR_DATALEN6;
630                 DPRINTF("  6 bit\n");
631                 break;
632         case CS7:
633                 lcr |= MCS7840_UART_LCR_DATALEN7;
634                 DPRINTF("  7 bit\n");
635                 break;
636         case CS8:
637                 lcr |= MCS7840_UART_LCR_DATALEN8;
638                 DPRINTF("  8 bit\n");
639                 break;
640         }
641
642         if (t->c_cflag & CRTSCTS) {
643                 mcr |= MCS7840_UART_MCR_CTSRTS;
644                 DPRINTF("  CTS/RTS\n");
645         } else
646                 mcr &= ~MCS7840_UART_MCR_CTSRTS;
647
648         if (t->c_cflag & (CDTR_IFLOW | CDSR_OFLOW)) {
649                 mcr |= MCS7840_UART_MCR_DTRDSR;
650                 DPRINTF("  DTR/DSR\n");
651         } else
652                 mcr &= ~MCS7840_UART_MCR_DTRDSR;
653
654         sc->sc_ports[pn].sc_lcr = lcr;
655         umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_LCR, sc->sc_ports[pn].sc_lcr);
656         DPRINTF("Port %d LCR=%02x\n", pn, sc->sc_ports[pn].sc_lcr);
657
658         sc->sc_ports[pn].sc_mcr = mcr;
659         umcs7840_set_UART_reg_sync(sc, pn, MCS7840_UART_REG_MCR, sc->sc_ports[pn].sc_mcr);
660         DPRINTF("Port %d MCR=%02x\n", pn, sc->sc_ports[pn].sc_mcr);
661
662         umcs7840_set_baudrate(sc, pn, t->c_ospeed);
663 }
664
665
666 static int
667 umcs7840_pre_param(struct ucom_softc *ucom, struct termios *t)
668 {
669         uint8_t clk;
670         uint16_t divisor;
671
672         if (umcs7840_calc_baudrate(t->c_ospeed, &divisor, &clk) || !divisor)
673                 return (EINVAL);
674         return (0);
675 }
676
677 static void
678 umcs7840_start_read(struct ucom_softc *ucom)
679 {
680         struct umcs7840_softc *sc = ucom->sc_parent;
681         uint8_t pn = ucom->sc_portno;
682
683         /* Start interrupt transfer */
684         usbd_transfer_start(sc->sc_intr_xfer);
685
686         /* Start read transfer */
687         usbd_transfer_start(sc->sc_ports[pn].sc_xfer[UMCS7840_BULK_RD_EP]);
688 }
689
690 static void
691 umcs7840_stop_read(struct ucom_softc *ucom)
692 {
693         struct umcs7840_softc *sc = ucom->sc_parent;
694         uint8_t pn = ucom->sc_portno;
695
696         /* Stop read transfer */
697         usbd_transfer_stop(sc->sc_ports[pn].sc_xfer[UMCS7840_BULK_RD_EP]);
698 }
699
700 static void
701 umcs7840_start_write(struct ucom_softc *ucom)
702 {
703         struct umcs7840_softc *sc = ucom->sc_parent;
704         uint8_t pn = ucom->sc_portno;
705
706         /* Start interrupt transfer */
707         usbd_transfer_start(sc->sc_intr_xfer);
708
709         /* Start write transfer */
710         usbd_transfer_start(sc->sc_ports[pn].sc_xfer[UMCS7840_BULK_WR_EP]);
711 }
712
713 static void
714 umcs7840_stop_write(struct ucom_softc *ucom)
715 {
716         struct umcs7840_softc *sc = ucom->sc_parent;
717         uint8_t pn = ucom->sc_portno;
718
719         /* Stop write transfer */
720         usbd_transfer_stop(sc->sc_ports[pn].sc_xfer[UMCS7840_BULK_WR_EP]);
721 }
722
723 static void
724 umcs7840_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
725 {
726         struct umcs7840_softc *sc = ucom->sc_parent;
727
728         *lsr = sc->sc_ports[ucom->sc_portno].sc_lsr;
729         *msr = sc->sc_ports[ucom->sc_portno].sc_msr;
730         DPRINTF("Port %d status: LSR=%02x MSR=%02x\n", ucom->sc_portno, *lsr, *msr);
731 }
732
733 static void
734 umcs7840_intr_callback(struct usb_xfer *xfer, usb_error_t error)
735 {
736         struct umcs7840_softc *sc = usbd_xfer_softc(xfer);
737         struct usb_page_cache *pc;
738         uint8_t buf[13];
739         int actlen;
740         int subunit;
741
742         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
743
744         switch (USB_GET_STATE(xfer)) {
745         case USB_ST_TRANSFERRED:
746                 if (actlen == 5 || actlen == 13) {
747                         pc = usbd_xfer_get_frame(xfer, 0);
748                         usbd_copy_out(pc, 0, buf, actlen);
749                         /* Check status of all ports */
750                         for (subunit = 0; subunit < sc->sc_numports; ++subunit) {
751                                 uint8_t pn = sc->sc_ucom[subunit].sc_portno;
752
753                                 if (buf[pn] & MCS7840_UART_ISR_NOPENDING)
754                                         continue;
755                                 DPRINTF("Port %d has pending interrupt: %02x (FIFO: %02x)\n", pn, buf[pn] & MCS7840_UART_ISR_INTMASK, buf[pn] & (~MCS7840_UART_ISR_INTMASK));
756                                 switch (buf[pn] & MCS7840_UART_ISR_INTMASK) {
757                                 case MCS7840_UART_ISR_RXERR:
758                                 case MCS7840_UART_ISR_RXHASDATA:
759                                 case MCS7840_UART_ISR_RXTIMEOUT:
760                                         /* Read new LSR */
761                                         if (umcs7840_get_UART_reg_sync(sc, pn, MCS7840_UART_REG_LSR, &sc->sc_ports[pn].sc_lsr))
762                                                 break;  /* Inner switch */
763                                         ucom_status_change(&sc->sc_ucom[subunit]);
764                                         /* Inner switch */
765                                         break;
766                                 case MCS7840_UART_ISR_TXEMPTY:
767                                         /* Do nothing */
768                                         break;  /* Inner switch */
769                                 case MCS7840_UART_ISR_MSCHANGE:
770                                         /* Read new MSR */
771                                         if (umcs7840_get_UART_reg_sync(sc, pn, MCS7840_UART_REG_MSR, &sc->sc_ports[pn].sc_msr))
772                                                 break;  /* Inner switch */
773                                         DPRINTF("Port %d: new MSR %02x\n", pn, sc->sc_ports[pn].sc_msr);
774                                         ucom_status_change(&sc->sc_ucom[subunit]);
775                                         break;
776                                 }
777                         }
778                 } else
779                         device_printf(sc->sc_dev, "Invalid interrupt data length %d", actlen);
780                 /* FALLTHROUGH */
781         case USB_ST_SETUP:
782 tr_setup:
783                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
784                 usbd_transfer_submit(xfer);
785                 return;
786
787         default:                        /* Error */
788                 if (error != USB_ERR_CANCELLED) {
789                         /* try to clear stall first */
790                         usbd_xfer_set_stall(xfer);
791                         goto tr_setup;
792                 }
793                 return;
794         }
795 }
796
797 static void
798 umcs7840_read_callback1(struct usb_xfer *xfer, usb_error_t error)
799 {
800         umcs7840_read_callbackN(xfer, error, 0);
801 }
802
803 static void
804 umcs7840_read_callback2(struct usb_xfer *xfer, usb_error_t error)
805 {
806         umcs7840_read_callbackN(xfer, error, 1);
807 }
808 static void
809 umcs7840_read_callback3(struct usb_xfer *xfer, usb_error_t error)
810 {
811         umcs7840_read_callbackN(xfer, error, 2);
812 }
813
814 static void
815 umcs7840_read_callback4(struct usb_xfer *xfer, usb_error_t error)
816 {
817         umcs7840_read_callbackN(xfer, error, 3);
818 }
819
820 static void
821 umcs7840_read_callbackN(struct usb_xfer *xfer, usb_error_t error, uint8_t subunit)
822 {
823         struct umcs7840_softc *sc = usbd_xfer_softc(xfer);
824         struct ucom_softc *ucom = &sc->sc_ucom[subunit];
825         struct usb_page_cache *pc;
826         int actlen;
827
828         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
829
830         DPRINTF("Port %d read, state = %d, data length = %d\n", ucom->sc_portno, USB_GET_STATE(xfer), actlen);
831
832         switch (USB_GET_STATE(xfer)) {
833         case USB_ST_TRANSFERRED:
834                 pc = usbd_xfer_get_frame(xfer, 0);
835                 ucom_put_data(ucom, pc, 0, actlen);
836                 /* FALLTHROUGH */
837         case USB_ST_SETUP:
838 tr_setup:
839                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
840                 usbd_transfer_submit(xfer);
841                 return;
842
843         default:                        /* Error */
844                 if (error != USB_ERR_CANCELLED) {
845                         /* try to clear stall first */
846                         usbd_xfer_set_stall(xfer);
847                         goto tr_setup;
848                 }
849                 return;
850         }
851 }
852
853 static void
854 umcs7840_write_callback1(struct usb_xfer *xfer, usb_error_t error)
855 {
856         umcs7840_write_callbackN(xfer, error, 0);
857 }
858
859 static void
860 umcs7840_write_callback2(struct usb_xfer *xfer, usb_error_t error)
861 {
862         umcs7840_write_callbackN(xfer, error, 1);
863 }
864
865 static void
866 umcs7840_write_callback3(struct usb_xfer *xfer, usb_error_t error)
867 {
868         umcs7840_write_callbackN(xfer, error, 2);
869 }
870
871 static void
872 umcs7840_write_callback4(struct usb_xfer *xfer, usb_error_t error)
873 {
874         umcs7840_write_callbackN(xfer, error, 3);
875 }
876
877 static void
878 umcs7840_write_callbackN(struct usb_xfer *xfer, usb_error_t error, uint8_t subunit)
879 {
880         struct umcs7840_softc *sc = usbd_xfer_softc(xfer);
881         struct ucom_softc *ucom = &sc->sc_ucom[subunit];
882         struct usb_page_cache *pc;
883         uint32_t actlen;
884
885         DPRINTF("Port %d write, state = %d\n", ucom->sc_portno, USB_GET_STATE(xfer));
886
887         switch (USB_GET_STATE(xfer)) {
888         case USB_ST_SETUP:
889         case USB_ST_TRANSFERRED:
890 tr_setup:
891                 pc = usbd_xfer_get_frame(xfer, 0);
892                 if (ucom_get_data(ucom, pc, 0, usbd_xfer_max_len(xfer), &actlen)) {
893                         DPRINTF("Port %d write, has %d bytes\n", ucom->sc_portno, actlen);
894                         usbd_xfer_set_frame_len(xfer, 0, actlen);
895                         usbd_transfer_submit(xfer);
896                 }
897                 return;
898
899         default:                        /* Error */
900                 if (error != USB_ERR_CANCELLED) {
901                         /* try to clear stall first */
902                         usbd_xfer_set_stall(xfer);
903                         goto tr_setup;
904                 }
905                 return;
906         }
907 }
908
909 static void
910 umcs7840_poll(struct ucom_softc *ucom)
911 {
912         struct umcs7840_softc *sc = ucom->sc_parent;
913
914         DPRINTF("Port %d poll\n", ucom->sc_portno);
915         usbd_transfer_poll(sc->sc_ports[ucom->sc_portno].sc_xfer, UMCS7840_N_TRANSFERS);
916         usbd_transfer_poll(&sc->sc_intr_xfer, 1);
917 }
918
919 static usb_error_t
920 umcs7840_get_reg_sync(struct umcs7840_softc *sc, uint8_t reg, uint8_t *data)
921 {
922         struct usb_device_request req;
923         usb_error_t err;
924         uint16_t len;
925
926         req.bmRequestType = UT_READ_VENDOR_DEVICE;
927         req.bRequest = MCS7840_RDREQ;
928         USETW(req.wValue, 0);
929         USETW(req.wIndex, reg);
930         USETW(req.wLength, UMCS7840_READ_LENGTH);
931
932         err = usbd_do_request_proc(sc->sc_udev, &sc->sc_super_ucom.sc_tq, &req, (void *)data, 0, &len, UMCS7840_CTRL_TIMEOUT);
933         if (err == USB_ERR_NORMAL_COMPLETION && len != 1) {
934                 device_printf(sc->sc_dev, "Reading register %d failed: invalid length %d\n", reg, len);
935                 return (USB_ERR_INVAL);
936         } else if (err)
937                 device_printf(sc->sc_dev, "Reading register %d failed: %s\n", reg, usbd_errstr(err));
938         return (err);
939 }
940
941 static usb_error_t
942 umcs7840_set_reg_sync(struct umcs7840_softc *sc, uint8_t reg, uint8_t data)
943 {
944         struct usb_device_request req;
945         usb_error_t err;
946
947         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
948         req.bRequest = MCS7840_WRREQ;
949         USETW(req.wValue, data);
950         USETW(req.wIndex, reg);
951         USETW(req.wLength, 0);
952
953         err = usbd_do_request_proc(sc->sc_udev, &sc->sc_super_ucom.sc_tq, &req, NULL, 0, NULL, UMCS7840_CTRL_TIMEOUT);
954         if (err)
955                 device_printf(sc->sc_dev, "Writing register %d failed: %s\n", reg, usbd_errstr(err));
956
957         return (err);
958 }
959
960 static usb_error_t
961 umcs7840_get_UART_reg_sync(struct umcs7840_softc *sc, uint8_t portno, uint8_t reg, uint8_t *data)
962 {
963         struct usb_device_request req;
964         uint16_t wVal;
965         usb_error_t err;
966         uint16_t len;
967
968         /* portno is port number */
969         wVal = ((uint16_t)(portno + 1)) << 8;
970
971         req.bmRequestType = UT_READ_VENDOR_DEVICE;
972         req.bRequest = MCS7840_RDREQ;
973         USETW(req.wValue, wVal);
974         USETW(req.wIndex, reg);
975         USETW(req.wLength, UMCS7840_READ_LENGTH);
976
977         err = usbd_do_request_proc(sc->sc_udev, &sc->sc_super_ucom.sc_tq, &req, (void *)data, 0, &len, UMCS7840_CTRL_TIMEOUT);
978         if (err == USB_ERR_NORMAL_COMPLETION && len != 1) {
979                 device_printf(sc->sc_dev, "Reading UART%d register %d failed: invalid length %d\n", portno, reg, len);
980                 return (USB_ERR_INVAL);
981         } else if (err)
982                 device_printf(sc->sc_dev, "Reading UART%d register %d failed: %s\n", portno, reg, usbd_errstr(err));
983         return (err);
984 }
985
986 static usb_error_t
987 umcs7840_set_UART_reg_sync(struct umcs7840_softc *sc, uint8_t portno, uint8_t reg, uint8_t data)
988 {
989         struct usb_device_request req;
990         usb_error_t err;
991         uint16_t wVal;
992
993         /* portno is port number */
994         wVal = ((uint16_t)(portno + 1)) << 8 | data;
995
996         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
997         req.bRequest = MCS7840_WRREQ;
998         USETW(req.wValue, wVal);
999         USETW(req.wIndex, reg);
1000         USETW(req.wLength, 0);
1001
1002         err = usbd_do_request_proc(sc->sc_udev, &sc->sc_super_ucom.sc_tq, &req, NULL, 0, NULL, UMCS7840_CTRL_TIMEOUT);
1003         if (err)
1004                 device_printf(sc->sc_dev, "Writing UART%d register %d failed: %s\n", portno, reg, usbd_errstr(err));
1005         return (err);
1006 }
1007
1008 static usb_error_t
1009 umcs7840_set_baudrate(struct umcs7840_softc *sc, uint8_t portno, uint32_t rate)
1010 {
1011         usb_error_t err;
1012         uint16_t divisor;
1013         uint8_t clk;
1014         uint8_t data;
1015
1016         if (umcs7840_calc_baudrate(rate, &divisor, &clk)) {
1017                 DPRINTF("Port %d bad speed: %d\n", portno, rate);
1018                 return (-1);
1019         }
1020         if (divisor == 0 || (clk & MCS7840_DEV_SPx_CLOCK_MASK) != clk) {
1021                 DPRINTF("Port %d bad speed calculation: %d\n", portno, rate);
1022                 return (-1);
1023         }
1024         DPRINTF("Port %d set speed: %d (%02x / %d)\n", portno, rate, clk, divisor);
1025
1026         /* Set clock source for standard BAUD frequences */
1027         err = umcs7840_get_reg_sync(sc, umcs7840_port_registers[portno].reg_sp, &data);
1028         if (err)
1029                 return (err);
1030         data &= MCS7840_DEV_SPx_CLOCK_MASK;
1031         data |= clk;
1032         err = umcs7840_set_reg_sync(sc, umcs7840_port_registers[portno].reg_sp, data);
1033         if (err)
1034                 return (err);
1035
1036         /* Set divider */
1037         sc->sc_ports[portno].sc_lcr |= MCS7840_UART_LCR_DIVISORS;
1038         err = umcs7840_set_UART_reg_sync(sc, portno, MCS7840_UART_REG_LCR, sc->sc_ports[portno].sc_lcr);
1039         if (err)
1040                 return (err);
1041
1042         err = umcs7840_set_UART_reg_sync(sc, portno, MCS7840_UART_REG_DLL, (uint8_t)(divisor & 0xff));
1043         if (err)
1044                 return (err);
1045         err = umcs7840_set_UART_reg_sync(sc, portno, MCS7840_UART_REG_DLM, (uint8_t)((divisor >> 8) & 0xff));
1046         if (err)
1047                 return (err);
1048
1049         /* Turn off access to DLL/DLM registers of UART */
1050         sc->sc_ports[portno].sc_lcr &= ~MCS7840_UART_LCR_DIVISORS;
1051         err = umcs7840_set_UART_reg_sync(sc, portno, MCS7840_UART_REG_LCR, sc->sc_ports[portno].sc_lcr);
1052         if (err)
1053                 return (err);
1054         return (0);
1055 }
1056
1057 /* Maximum speeds for standard frequences, when PLL is not used */
1058 static const uint32_t umcs7840_baudrate_divisors[] = {0, 115200, 230400, 403200, 460800, 806400, 921600, 1572864, 3145728,};
1059 static const uint8_t umcs7840_baudrate_divisors_len = sizeof(umcs7840_baudrate_divisors) / sizeof(umcs7840_baudrate_divisors[0]);
1060
1061 static usb_error_t
1062 umcs7840_calc_baudrate(uint32_t rate, uint16_t *divisor, uint8_t *clk)
1063 {
1064         uint8_t i = 0;
1065
1066         if (rate > umcs7840_baudrate_divisors[umcs7840_baudrate_divisors_len - 1])
1067                 return (-1);
1068
1069         for (i = 0; i < umcs7840_baudrate_divisors_len - 1 &&
1070             !(rate > umcs7840_baudrate_divisors[i] && rate <= umcs7840_baudrate_divisors[i + 1]); ++i);
1071         *divisor = umcs7840_baudrate_divisors[i + 1] / rate;
1072         /* 0x00 .. 0x70 */
1073         *clk = i << MCS7840_DEV_SPx_CLOCK_SHIFT;
1074         return (0);
1075 }