uchcom.c revision 1.25 1 /* $NetBSD: uchcom.c,v 1.25 2018/12/12 23:26:00 jakllsch Exp $ */
2
3 /*
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Takuya SHIOZAKI (tshiozak (at) netbsd.org).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: uchcom.c,v 1.25 2018/12/12 23:26:00 jakllsch Exp $");
34
35 #ifdef _KERNEL_OPT
36 #include "opt_usb.h"
37 #endif
38
39 /*
40 * driver for WinChipHead CH341/340, the worst USB-serial chip in the world.
41 */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/kmem.h>
47 #include <sys/ioctl.h>
48 #include <sys/conf.h>
49 #include <sys/tty.h>
50 #include <sys/file.h>
51 #include <sys/select.h>
52 #include <sys/proc.h>
53 #include <sys/device.h>
54 #include <sys/poll.h>
55
56 #include <dev/usb/usb.h>
57
58 #include <dev/usb/usbdi.h>
59 #include <dev/usb/usbdi_util.h>
60 #include <dev/usb/usbdevs.h>
61
62 #include <dev/usb/ucomvar.h>
63
64 #ifdef UCHCOM_DEBUG
65 #define DPRINTFN(n, x) if (uchcomdebug > (n)) printf x
66 int uchcomdebug = 0;
67 #else
68 #define DPRINTFN(n, x)
69 #endif
70 #define DPRINTF(x) DPRINTFN(0, x)
71
72 #define UCHCOM_IFACE_INDEX 0
73 #define UCHCOM_CONFIG_INDEX 0
74
75 #define UCHCOM_INPUT_BUF_SIZE 8
76
77 #define UCHCOM_REQ_GET_VERSION 0x5F
78 #define UCHCOM_REQ_READ_REG 0x95
79 #define UCHCOM_REQ_WRITE_REG 0x9A
80 #define UCHCOM_REQ_RESET 0xA1
81 #define UCHCOM_REQ_SET_DTRRTS 0xA4
82
83 #define UCHCOM_REG_STAT1 0x06
84 #define UCHCOM_REG_STAT2 0x07
85 #define UCHCOM_REG_BPS_PRE 0x12
86 #define UCHCOM_REG_BPS_DIV 0x13
87 #define UCHCOM_REG_BREAK1 0x05
88 #define UCHCOM_REG_BREAK2 0x18
89 #define UCHCOM_REG_LCR1 0x18
90 #define UCHCOM_REG_LCR2 0x25
91
92 #define UCHCOM_VER_20 0x20
93 #define UCHCOM_VER_30 0x30
94
95 #define UCHCOM_BASE_UNKNOWN 0
96
97 #define UCHCOM_BPS_PRE_IMM 0x80 /* CH341: immediate RX forwarding */
98
99 #define UCHCOM_DTR_MASK 0x20
100 #define UCHCOM_RTS_MASK 0x40
101
102 #define UCHCOM_BRK1_MASK 0x01
103 #define UCHCOM_BRK2_MASK 0x40
104
105 #define UCHCOM_LCR1_MASK 0xAF
106 #define UCHCOM_LCR2_MASK 0x07
107 #define UCHCOM_LCR1_PARENB 0x80
108 #define UCHCOM_LCR2_PAREVEN 0x07
109 #define UCHCOM_LCR2_PARODD 0x06
110 #define UCHCOM_LCR2_PARMARK 0x05
111 #define UCHCOM_LCR2_PARSPACE 0x04
112
113 #define UCHCOM_INTR_STAT1 0x02
114 #define UCHCOM_INTR_STAT2 0x03
115 #define UCHCOM_INTR_LEAST 4
116
117 #define UCHCOMIBUFSIZE 256
118 #define UCHCOMOBUFSIZE 256
119
120 struct uchcom_softc
121 {
122 device_t sc_dev;
123 struct usbd_device * sc_udev;
124 device_t sc_subdev;
125 struct usbd_interface * sc_iface;
126 int sc_dying;
127 /* */
128 int sc_intr_endpoint;
129 int sc_intr_size;
130 struct usbd_pipe * sc_intr_pipe;
131 u_char *sc_intr_buf;
132 /* */
133 uint8_t sc_version;
134 int sc_dtr;
135 int sc_rts;
136 u_char sc_lsr;
137 u_char sc_msr;
138 };
139
140 struct uchcom_endpoints
141 {
142 int ep_bulkin;
143 int ep_bulkout;
144 int ep_intr;
145 int ep_intr_size;
146 };
147
148 struct uchcom_divider
149 {
150 uint8_t dv_prescaler;
151 uint8_t dv_div;
152 };
153
154 struct uchcom_divider_record
155 {
156 uint32_t dvr_high;
157 uint32_t dvr_low;
158 uint32_t dvr_base_clock;
159 struct uchcom_divider dvr_divider;
160 };
161
162 static const struct uchcom_divider_record dividers[] =
163 {
164 { 307200, 307200, UCHCOM_BASE_UNKNOWN, { 7, 0xD9 } },
165 { 921600, 921600, UCHCOM_BASE_UNKNOWN, { 7, 0xF3 } },
166 { 2999999, 23530, 6000000, { 3, 0 } },
167 { 23529, 2942, 750000, { 2, 0 } },
168 { 2941, 368, 93750, { 1, 0 } },
169 { 367, 1, 11719, { 0, 0 } },
170 };
171 #define NUM_DIVIDERS (sizeof (dividers) / sizeof (dividers[0]))
172
173 static const struct usb_devno uchcom_devs[] = {
174 { USB_VENDOR_QINHENG2, USB_PRODUCT_QINHENG2_CH341SER },
175 { USB_VENDOR_QINHENG, USB_PRODUCT_QINHENG_CH340 },
176 { USB_VENDOR_QINHENG, USB_PRODUCT_QINHENG_CH341_ASP },
177 };
178 #define uchcom_lookup(v, p) usb_lookup(uchcom_devs, v, p)
179
180 Static void uchcom_get_status(void *, int, u_char *, u_char *);
181 Static void uchcom_set(void *, int, int, int);
182 Static int uchcom_param(void *, int, struct termios *);
183 Static int uchcom_open(void *, int);
184 Static void uchcom_close(void *, int);
185 Static void uchcom_intr(struct usbd_xfer *, void *,
186 usbd_status);
187
188 static int set_config(struct uchcom_softc *);
189 static int find_ifaces(struct uchcom_softc *, struct usbd_interface **);
190 static int find_endpoints(struct uchcom_softc *,
191 struct uchcom_endpoints *);
192 static void close_intr_pipe(struct uchcom_softc *);
193
194
195 struct ucom_methods uchcom_methods = {
196 .ucom_get_status = uchcom_get_status,
197 .ucom_set = uchcom_set,
198 .ucom_param = uchcom_param,
199 .ucom_ioctl = NULL,
200 .ucom_open = uchcom_open,
201 .ucom_close = uchcom_close,
202 .ucom_read = NULL,
203 .ucom_write = NULL,
204 };
205
206 int uchcom_match(device_t, cfdata_t, void *);
207 void uchcom_attach(device_t, device_t, void *);
208 void uchcom_childdet(device_t, device_t);
209 int uchcom_detach(device_t, int);
210 int uchcom_activate(device_t, enum devact);
211
212 extern struct cfdriver uchcom_cd;
213
214 CFATTACH_DECL2_NEW(uchcom,
215 sizeof(struct uchcom_softc),
216 uchcom_match,
217 uchcom_attach,
218 uchcom_detach,
219 uchcom_activate,
220 NULL,
221 uchcom_childdet);
222
223 /* ----------------------------------------------------------------------
224 * driver entry points
225 */
226
227 int
228 uchcom_match(device_t parent, cfdata_t match, void *aux)
229 {
230 struct usb_attach_arg *uaa = aux;
231
232 return (uchcom_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ?
233 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
234 }
235
236 void
237 uchcom_attach(device_t parent, device_t self, void *aux)
238 {
239 struct uchcom_softc *sc = device_private(self);
240 struct usb_attach_arg *uaa = aux;
241 struct usbd_device *dev = uaa->uaa_device;
242 char *devinfop;
243 struct uchcom_endpoints endpoints;
244 struct ucom_attach_args ucaa;
245
246 aprint_naive("\n");
247 aprint_normal("\n");
248
249 devinfop = usbd_devinfo_alloc(dev, 0);
250 aprint_normal_dev(self, "%s\n", devinfop);
251 usbd_devinfo_free(devinfop);
252
253 sc->sc_dev = self;
254 sc->sc_udev = dev;
255 sc->sc_dying = 0;
256 sc->sc_dtr = sc->sc_rts = -1;
257 sc->sc_lsr = sc->sc_msr = 0;
258
259 DPRINTF(("\n\nuchcom attach: sc=%p\n", sc));
260
261 if (set_config(sc))
262 goto failed;
263
264 if (find_ifaces(sc, &sc->sc_iface))
265 goto failed;
266
267 if (find_endpoints(sc, &endpoints))
268 goto failed;
269
270 sc->sc_intr_endpoint = endpoints.ep_intr;
271 sc->sc_intr_size = endpoints.ep_intr_size;
272
273 /* setup ucom layer */
274 ucaa.ucaa_portno = UCOM_UNK_PORTNO;
275 ucaa.ucaa_bulkin = endpoints.ep_bulkin;
276 ucaa.ucaa_bulkout = endpoints.ep_bulkout;
277 ucaa.ucaa_ibufsize = UCHCOMIBUFSIZE;
278 ucaa.ucaa_obufsize = UCHCOMOBUFSIZE;
279 ucaa.ucaa_ibufsizepad = UCHCOMIBUFSIZE;
280 ucaa.ucaa_opkthdrlen = 0;
281 ucaa.ucaa_device = dev;
282 ucaa.ucaa_iface = sc->sc_iface;
283 ucaa.ucaa_methods = &uchcom_methods;
284 ucaa.ucaa_arg = sc;
285 ucaa.ucaa_info = NULL;
286
287 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);
288
289 sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, &ucaa,
290 ucomprint, ucomsubmatch);
291
292 return;
293
294 failed:
295 sc->sc_dying = 1;
296 return;
297 }
298
299 void
300 uchcom_childdet(device_t self, device_t child)
301 {
302 struct uchcom_softc *sc = device_private(self);
303
304 KASSERT(sc->sc_subdev == child);
305 sc->sc_subdev = NULL;
306 }
307
308 int
309 uchcom_detach(device_t self, int flags)
310 {
311 struct uchcom_softc *sc = device_private(self);
312 int rv = 0;
313
314 DPRINTF(("uchcom_detach: sc=%p flags=%d\n", sc, flags));
315
316 close_intr_pipe(sc);
317
318 sc->sc_dying = 1;
319
320 if (sc->sc_subdev != NULL)
321 rv = config_detach(sc->sc_subdev, flags);
322
323 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
324
325 return rv;
326 }
327
328 int
329 uchcom_activate(device_t self, enum devact act)
330 {
331 struct uchcom_softc *sc = device_private(self);
332
333 switch (act) {
334 case DVACT_DEACTIVATE:
335 close_intr_pipe(sc);
336 sc->sc_dying = 1;
337 return 0;
338 default:
339 return EOPNOTSUPP;
340 }
341 }
342
343 static int
344 set_config(struct uchcom_softc *sc)
345 {
346 usbd_status err;
347
348 err = usbd_set_config_index(sc->sc_udev, UCHCOM_CONFIG_INDEX, 1);
349 if (err) {
350 aprint_error_dev(sc->sc_dev,
351 "failed to set configuration: %s\n", usbd_errstr(err));
352 return -1;
353 }
354
355 return 0;
356 }
357
358 static int
359 find_ifaces(struct uchcom_softc *sc, struct usbd_interface **riface)
360 {
361 usbd_status err;
362
363 err = usbd_device2interface_handle(sc->sc_udev, UCHCOM_IFACE_INDEX,
364 riface);
365 if (err) {
366 aprint_error("\n%s: failed to get interface: %s\n",
367 device_xname(sc->sc_dev), usbd_errstr(err));
368 return -1;
369 }
370
371 return 0;
372 }
373
374 static int
375 find_endpoints(struct uchcom_softc *sc, struct uchcom_endpoints *endpoints)
376 {
377 int i, bin=-1, bout=-1, intr=-1, isize=0;
378 usb_interface_descriptor_t *id;
379 usb_endpoint_descriptor_t *ed;
380
381 id = usbd_get_interface_descriptor(sc->sc_iface);
382
383 for (i = 0; i < id->bNumEndpoints; i++) {
384 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
385 if (ed == NULL) {
386 aprint_error_dev(sc->sc_dev,
387 "no endpoint descriptor for %d\n", i);
388 return -1;
389 }
390
391 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
392 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
393 intr = ed->bEndpointAddress;
394 isize = UGETW(ed->wMaxPacketSize);
395 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
396 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
397 bin = ed->bEndpointAddress;
398 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
399 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
400 bout = ed->bEndpointAddress;
401 }
402 }
403
404 if (intr == -1 || bin == -1 || bout == -1) {
405 if (intr == -1) {
406 aprint_error_dev(sc->sc_dev,
407 "no interrupt end point\n");
408 }
409 if (bin == -1) {
410 aprint_error_dev(sc->sc_dev,
411 "no data bulk in end point\n");
412 }
413 if (bout == -1) {
414 aprint_error_dev(sc->sc_dev,
415 "no data bulk out end point\n");
416 }
417 return -1;
418 }
419 if (isize < UCHCOM_INTR_LEAST) {
420 aprint_error_dev(sc->sc_dev, "intr pipe is too short\n");
421 return -1;
422 }
423
424 DPRINTF(("%s: bulkin=%d, bulkout=%d, intr=%d, isize=%d\n",
425 device_xname(sc->sc_dev), bin, bout, intr, isize));
426
427 endpoints->ep_intr = intr;
428 endpoints->ep_intr_size = isize;
429 endpoints->ep_bulkin = bin;
430 endpoints->ep_bulkout = bout;
431
432 return 0;
433 }
434
435
436 /* ----------------------------------------------------------------------
437 * low level i/o
438 */
439
440 static __inline usbd_status
441 generic_control_out(struct uchcom_softc *sc, uint8_t reqno,
442 uint16_t value, uint16_t index)
443 {
444 usb_device_request_t req;
445
446 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
447 req.bRequest = reqno;
448 USETW(req.wValue, value);
449 USETW(req.wIndex, index);
450 USETW(req.wLength, 0);
451
452 return usbd_do_request(sc->sc_udev, &req, 0);
453 }
454
455 static __inline usbd_status
456 generic_control_in(struct uchcom_softc *sc, uint8_t reqno,
457 uint16_t value, uint16_t index, void *buf, int buflen,
458 int *actlen)
459 {
460 usb_device_request_t req;
461
462 req.bmRequestType = UT_READ_VENDOR_DEVICE;
463 req.bRequest = reqno;
464 USETW(req.wValue, value);
465 USETW(req.wIndex, index);
466 USETW(req.wLength, (uint16_t)buflen);
467
468 return usbd_do_request_flags(sc->sc_udev, &req, buf,
469 USBD_SHORT_XFER_OK, actlen,
470 USBD_DEFAULT_TIMEOUT);
471 }
472
473 static __inline usbd_status
474 write_reg(struct uchcom_softc *sc,
475 uint8_t reg1, uint8_t val1, uint8_t reg2, uint8_t val2)
476 {
477 DPRINTF(("%s: write reg 0x%02X<-0x%02X, 0x%02X<-0x%02X\n",
478 device_xname(sc->sc_dev),
479 (unsigned)reg1, (unsigned)val1,
480 (unsigned)reg2, (unsigned)val2));
481 return generic_control_out(
482 sc, UCHCOM_REQ_WRITE_REG,
483 reg1|((uint16_t)reg2<<8), val1|((uint16_t)val2<<8));
484 }
485
486 static __inline usbd_status
487 read_reg(struct uchcom_softc *sc,
488 uint8_t reg1, uint8_t *rval1, uint8_t reg2, uint8_t *rval2)
489 {
490 uint8_t buf[UCHCOM_INPUT_BUF_SIZE];
491 usbd_status err;
492 int actin;
493
494 err = generic_control_in(
495 sc, UCHCOM_REQ_READ_REG,
496 reg1|((uint16_t)reg2<<8), 0, buf, sizeof(buf), &actin);
497 if (err)
498 return err;
499
500 DPRINTF(("%s: read reg 0x%02X->0x%02X, 0x%02X->0x%02X\n",
501 device_xname(sc->sc_dev),
502 (unsigned)reg1, (unsigned)buf[0],
503 (unsigned)reg2, (unsigned)buf[1]));
504
505 if (rval1) *rval1 = buf[0];
506 if (rval2) *rval2 = buf[1];
507
508 return USBD_NORMAL_COMPLETION;
509 }
510
511 static __inline usbd_status
512 get_version(struct uchcom_softc *sc, uint8_t *rver)
513 {
514 uint8_t buf[UCHCOM_INPUT_BUF_SIZE];
515 usbd_status err;
516 int actin;
517
518 err = generic_control_in(
519 sc, UCHCOM_REQ_GET_VERSION, 0, 0, buf, sizeof(buf), &actin);
520 if (err)
521 return err;
522
523 if (rver) *rver = buf[0];
524
525 return USBD_NORMAL_COMPLETION;
526 }
527
528 static __inline usbd_status
529 get_status(struct uchcom_softc *sc, uint8_t *rval)
530 {
531 return read_reg(sc, UCHCOM_REG_STAT1, rval, UCHCOM_REG_STAT2, NULL);
532 }
533
534 static __inline usbd_status
535 set_dtrrts_10(struct uchcom_softc *sc, uint8_t val)
536 {
537 return write_reg(sc, UCHCOM_REG_STAT1, val, UCHCOM_REG_STAT1, val);
538 }
539
540 static __inline usbd_status
541 set_dtrrts_20(struct uchcom_softc *sc, uint8_t val)
542 {
543 return generic_control_out(sc, UCHCOM_REQ_SET_DTRRTS, val, 0);
544 }
545
546
547 /* ----------------------------------------------------------------------
548 * middle layer
549 */
550
551 static int
552 update_version(struct uchcom_softc *sc)
553 {
554 usbd_status err;
555
556 err = get_version(sc, &sc->sc_version);
557 if (err) {
558 device_printf(sc->sc_dev, "cannot get version: %s\n",
559 usbd_errstr(err));
560 return EIO;
561 }
562 DPRINTF(("%s: update_version %d\n", device_xname(sc->sc_dev), sc->sc_version));
563
564 return 0;
565 }
566
567 static void
568 convert_status(struct uchcom_softc *sc, uint8_t cur)
569 {
570 sc->sc_dtr = !(cur & UCHCOM_DTR_MASK);
571 sc->sc_rts = !(cur & UCHCOM_RTS_MASK);
572
573 cur = ~cur & 0x0F;
574 sc->sc_msr = (cur << 4) | ((sc->sc_msr >> 4) ^ cur);
575 }
576
577 static int
578 update_status(struct uchcom_softc *sc)
579 {
580 usbd_status err;
581 uint8_t cur;
582
583 err = get_status(sc, &cur);
584 if (err) {
585 device_printf(sc->sc_dev,
586 "cannot update status: %s\n", usbd_errstr(err));
587 return EIO;
588 }
589 convert_status(sc, cur);
590
591 return 0;
592 }
593
594
595 static int
596 set_dtrrts(struct uchcom_softc *sc, int dtr, int rts)
597 {
598 usbd_status err;
599 uint8_t val = 0;
600
601 if (dtr) val |= UCHCOM_DTR_MASK;
602 if (rts) val |= UCHCOM_RTS_MASK;
603
604 if (sc->sc_version < UCHCOM_VER_20)
605 err = set_dtrrts_10(sc, ~val);
606 else
607 err = set_dtrrts_20(sc, ~val);
608
609 if (err) {
610 device_printf(sc->sc_dev, "cannot set DTR/RTS: %s\n",
611 usbd_errstr(err));
612 return EIO;
613 }
614
615 return 0;
616 }
617
618 static int
619 set_break(struct uchcom_softc *sc, int onoff)
620 {
621 usbd_status err;
622 uint8_t brk1, brk2;
623
624 err = read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_BREAK2, &brk2);
625 if (err)
626 return EIO;
627 if (onoff) {
628 /* on - clear bits */
629 brk1 &= ~UCHCOM_BRK1_MASK;
630 brk2 &= ~UCHCOM_BRK2_MASK;
631 } else {
632 /* off - set bits */
633 brk1 |= UCHCOM_BRK1_MASK;
634 brk2 |= UCHCOM_BRK2_MASK;
635 }
636 err = write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_BREAK2, brk2);
637 if (err)
638 return EIO;
639
640 return 0;
641 }
642
643 static int
644 calc_divider_settings(struct uchcom_divider *dp, uint32_t rate)
645 {
646 int i;
647 const struct uchcom_divider_record *rp;
648 uint32_t div, rem;
649
650 /* find record */
651 for (i=0; i<NUM_DIVIDERS; i++) {
652 if (dividers[i].dvr_high >= rate &&
653 dividers[i].dvr_low <= rate) {
654 rp = ÷rs[i];
655 goto found;
656 }
657 }
658 return -1;
659
660 found:
661 dp->dv_prescaler = rp->dvr_divider.dv_prescaler;
662 if (rp->dvr_base_clock == UCHCOM_BASE_UNKNOWN)
663 dp->dv_div = rp->dvr_divider.dv_div;
664 else {
665 div = rp->dvr_base_clock / rate;
666 rem = rp->dvr_base_clock % rate;
667 if (div==0 || div>=0xFF)
668 return -1;
669 if ((rem<<1) >= rate)
670 div += 1;
671 dp->dv_div = (uint8_t)-div;
672 }
673
674 return 0;
675 }
676
677 static int
678 set_dte_rate(struct uchcom_softc *sc, uint32_t rate)
679 {
680 usbd_status err;
681 struct uchcom_divider dv;
682
683 if (calc_divider_settings(&dv, rate))
684 return EINVAL;
685
686 if ((err = write_reg(sc,
687 UCHCOM_REG_BPS_PRE,
688 dv.dv_prescaler | UCHCOM_BPS_PRE_IMM,
689 UCHCOM_REG_BPS_DIV, dv.dv_div))) {
690 device_printf(sc->sc_dev, "cannot set DTE rate: %s\n",
691 usbd_errstr(err));
692 return EIO;
693 }
694
695 return 0;
696 }
697
698 static int
699 set_line_control(struct uchcom_softc *sc, tcflag_t cflag)
700 {
701 if (sc->sc_version < UCHCOM_VER_30) {
702 usbd_status err;
703 uint8_t lcr1val = 0, lcr2val = 0;
704
705 err = read_reg(sc, UCHCOM_REG_LCR1, &lcr1val, UCHCOM_REG_LCR2, &lcr2val);
706 if (err) {
707 device_printf(sc->sc_dev, "cannot get LCR: %s\n",
708 usbd_errstr(err));
709 return EIO;
710 }
711
712 lcr1val &= ~UCHCOM_LCR1_MASK;
713 lcr2val &= ~UCHCOM_LCR2_MASK;
714
715 /*
716 * XXX: it is difficult to handle the line control appropriately:
717 * - CS8, !CSTOPB and any parity mode seems ok, but
718 * - the chip doesn't have the function to calculate parity
719 * in !CS8 mode.
720 * - it is unclear that the chip supports CS5,6 mode.
721 * - it is unclear how to handle stop bits.
722 */
723
724 switch (ISSET(cflag, CSIZE)) {
725 case CS5:
726 case CS6:
727 case CS7:
728 return EINVAL;
729 case CS8:
730 break;
731 }
732
733 if (ISSET(cflag, PARENB)) {
734 lcr1val |= UCHCOM_LCR1_PARENB;
735 if (ISSET(cflag, PARODD))
736 lcr2val |= UCHCOM_LCR2_PARODD;
737 else
738 lcr2val |= UCHCOM_LCR2_PAREVEN;
739 }
740
741 err = write_reg(sc, UCHCOM_REG_LCR1, lcr1val, UCHCOM_REG_LCR2, lcr2val);
742 if (err) {
743 device_printf(sc->sc_dev, "cannot set LCR: %s\n",
744 usbd_errstr(err));
745 return EIO;
746 }
747 }
748
749 return 0;
750 }
751
752 static int
753 clear_chip(struct uchcom_softc *sc)
754 {
755 usbd_status err;
756
757 DPRINTF(("%s: clear\n", device_xname(sc->sc_dev)));
758 err = generic_control_out(sc, UCHCOM_REQ_RESET, 0, 0);
759 if (err) {
760 device_printf(sc->sc_dev, "cannot clear: %s\n",
761 usbd_errstr(err));
762 return EIO;
763 }
764
765 return 0;
766 }
767
768 static int
769 reset_chip(struct uchcom_softc *sc)
770 {
771 usbd_status err;
772 uint8_t lcr1val, lcr2val, pre, div;
773 uint16_t val=0, idx=0;
774
775 err = read_reg(sc, UCHCOM_REG_LCR1, &lcr1val, UCHCOM_REG_LCR2, &lcr2val);
776 if (err)
777 goto failed;
778
779 err = read_reg(sc, UCHCOM_REG_BPS_PRE, &pre, UCHCOM_REG_BPS_DIV, &div);
780 if (err)
781 goto failed;
782
783 val |= (uint16_t)(lcr1val&0xF0) << 8;
784 val |= 0x01;
785 val |= (uint16_t)(lcr2val&0x0F) << 8;
786 val |= 0x02;
787 idx |= pre & 0x07;
788 val |= 0x04;
789 idx |= (uint16_t)div << 8;
790 val |= 0x08;
791 val |= 0x10;
792
793 DPRINTF(("%s: reset v=0x%04X, i=0x%04X\n",
794 device_xname(sc->sc_dev), val, idx));
795
796 err = generic_control_out(sc, UCHCOM_REQ_RESET, val, idx);
797 if (err)
798 goto failed;
799
800 return 0;
801
802 failed:
803 printf("%s: cannot reset: %s\n",
804 device_xname(sc->sc_dev), usbd_errstr(err));
805 return EIO;
806 }
807
808 static int
809 setup_comm(struct uchcom_softc *sc)
810 {
811 int ret;
812
813 ret = update_version(sc);
814 if (ret)
815 return ret;
816
817 ret = clear_chip(sc);
818 if (ret)
819 return ret;
820
821 ret = set_dte_rate(sc, TTYDEF_SPEED);
822 if (ret)
823 return ret;
824
825 ret = set_line_control(sc, CS8);
826 if (ret)
827 return ret;
828
829 ret = update_status(sc);
830 if (ret)
831 return ret;
832
833 ret = reset_chip(sc);
834 if (ret)
835 return ret;
836
837 ret = set_dte_rate(sc, TTYDEF_SPEED); /* XXX */
838 if (ret)
839 return ret;
840
841 sc->sc_dtr = sc->sc_rts = 1;
842 ret = set_dtrrts(sc, sc->sc_dtr, sc->sc_rts);
843 if (ret)
844 return ret;
845
846 return 0;
847 }
848
849 static int
850 setup_intr_pipe(struct uchcom_softc *sc)
851 {
852 usbd_status err;
853
854 if (sc->sc_intr_endpoint != -1 && sc->sc_intr_pipe == NULL) {
855 sc->sc_intr_buf = kmem_alloc(sc->sc_intr_size, KM_SLEEP);
856 err = usbd_open_pipe_intr(sc->sc_iface,
857 sc->sc_intr_endpoint,
858 USBD_SHORT_XFER_OK,
859 &sc->sc_intr_pipe, sc,
860 sc->sc_intr_buf,
861 sc->sc_intr_size,
862 uchcom_intr, USBD_DEFAULT_INTERVAL);
863 if (err) {
864 device_printf(sc->sc_dev,
865 "cannot open interrupt pipe: %s\n",
866 usbd_errstr(err));
867 return EIO;
868 }
869 }
870 return 0;
871 }
872
873 static void
874 close_intr_pipe(struct uchcom_softc *sc)
875 {
876 usbd_status err;
877
878 if (sc->sc_dying)
879 return;
880
881 if (sc->sc_intr_pipe != NULL) {
882 err = usbd_abort_pipe(sc->sc_intr_pipe);
883 if (err)
884 device_printf(sc->sc_dev,
885 "abort interrupt pipe failed: %s\n",
886 usbd_errstr(err));
887 err = usbd_close_pipe(sc->sc_intr_pipe);
888 if (err)
889 device_printf(sc->sc_dev,
890 "close interrupt pipe failed: %s\n",
891 usbd_errstr(err));
892 kmem_free(sc->sc_intr_buf, sc->sc_intr_size);
893 sc->sc_intr_pipe = NULL;
894 }
895 }
896
897
898 /* ----------------------------------------------------------------------
899 * methods for ucom
900 */
901 void
902 uchcom_get_status(void *arg, int portno, u_char *rlsr, u_char *rmsr)
903 {
904 struct uchcom_softc *sc = arg;
905
906 if (sc->sc_dying)
907 return;
908
909 *rlsr = sc->sc_lsr;
910 *rmsr = sc->sc_msr;
911 }
912
913 void
914 uchcom_set(void *arg, int portno, int reg, int onoff)
915 {
916 struct uchcom_softc *sc = arg;
917
918 if (sc->sc_dying)
919 return;
920
921 switch (reg) {
922 case UCOM_SET_DTR:
923 sc->sc_dtr = !!onoff;
924 set_dtrrts(sc, sc->sc_dtr, sc->sc_rts);
925 break;
926 case UCOM_SET_RTS:
927 sc->sc_rts = !!onoff;
928 set_dtrrts(sc, sc->sc_dtr, sc->sc_rts);
929 break;
930 case UCOM_SET_BREAK:
931 set_break(sc, onoff);
932 break;
933 }
934 }
935
936 int
937 uchcom_param(void *arg, int portno, struct termios *t)
938 {
939 struct uchcom_softc *sc = arg;
940 int ret;
941
942 if (sc->sc_dying)
943 return 0;
944
945 ret = set_line_control(sc, t->c_cflag);
946 if (ret)
947 return ret;
948
949 ret = set_dte_rate(sc, t->c_ospeed);
950 if (ret)
951 return ret;
952
953 return 0;
954 }
955
956 int
957 uchcom_open(void *arg, int portno)
958 {
959 int ret;
960 struct uchcom_softc *sc = arg;
961
962 if (sc->sc_dying)
963 return EIO;
964
965 ret = setup_intr_pipe(sc);
966 if (ret)
967 return ret;
968
969 ret = setup_comm(sc);
970 if (ret)
971 return ret;
972
973 return 0;
974 }
975
976 void
977 uchcom_close(void *arg, int portno)
978 {
979 struct uchcom_softc *sc = arg;
980
981 if (sc->sc_dying)
982 return;
983
984 close_intr_pipe(sc);
985 }
986
987
988 /* ----------------------------------------------------------------------
989 * callback when the modem status is changed.
990 */
991 void
992 uchcom_intr(struct usbd_xfer *xfer, void * priv,
993 usbd_status status)
994 {
995 struct uchcom_softc *sc = priv;
996 u_char *buf = sc->sc_intr_buf;
997
998 if (sc->sc_dying)
999 return;
1000
1001 if (status != USBD_NORMAL_COMPLETION) {
1002 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1003 return;
1004
1005 DPRINTF(("%s: abnormal status: %s\n",
1006 device_xname(sc->sc_dev), usbd_errstr(status)));
1007 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
1008 return;
1009 }
1010 DPRINTF(("%s: intr: 0x%02X 0x%02X 0x%02X 0x%02X "
1011 "0x%02X 0x%02X 0x%02X 0x%02X\n",
1012 device_xname(sc->sc_dev),
1013 (unsigned)buf[0], (unsigned)buf[1],
1014 (unsigned)buf[2], (unsigned)buf[3],
1015 (unsigned)buf[4], (unsigned)buf[5],
1016 (unsigned)buf[6], (unsigned)buf[7]));
1017
1018 convert_status(sc, buf[UCHCOM_INTR_STAT1]);
1019 ucom_status_change(device_private(sc->sc_subdev));
1020 }
1021