1 /* $NetBSD: uchcom.c,v 1.1 2007/09/03 17:57:37 tshiozak Exp $ */
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Takuya SHIOZAKI (tshiozak@netbsd.org).
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
40 * driver for WinChipHead CH341/340, the worst USB-serial chip in the world.
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/malloc.h>
49 #include <sys/device.h>
50 #include <sys/types.h>
52 #include <sys/module.h>
54 #include <bus/usb/usb.h>
55 #include <bus/usb/usbdi.h>
56 #include <bus/usb/usbdi_util.h>
58 #include <dev/usbmisc/ucom/ucomvar.h>
61 #define DPRINTFN(n, x) do { if (uchcomdebug > (n)) kprintf x; } while (0)
64 #define DPRINTFN(n, x)
66 #define DPRINTF(x) DPRINTFN(0, x)
68 #define UCHCOM_IFACE_INDEX 0
69 #define UCHCOM_CONFIG_INDEX 0
71 #define UCHCOM_REV_CH340 0x0250
72 #define UCHCOM_INPUT_BUF_SIZE 8
74 #define UCHCOM_REQ_GET_VERSION 0x5F
75 #define UCHCOM_REQ_READ_REG 0x95
76 #define UCHCOM_REQ_WRITE_REG 0x9A
77 #define UCHCOM_REQ_RESET 0xA1
78 #define UCHCOM_REQ_SET_DTRRTS 0xA4
80 #define UCHCOM_REG_STAT1 0x06
81 #define UCHCOM_REG_STAT2 0x07
82 #define UCHCOM_REG_BPS_PRE 0x12
83 #define UCHCOM_REG_BPS_DIV 0x13
84 #define UCHCOM_REG_BPS_MOD 0x14
85 #define UCHCOM_REG_BPS_PAD 0x0F
86 #define UCHCOM_REG_BREAK1 0x05
87 #define UCHCOM_REG_BREAK2 0x18
88 #define UCHCOM_REG_LCR1 0x18
89 #define UCHCOM_REG_LCR2 0x25
91 #define UCHCOM_VER_20 0x20
93 #define UCHCOM_BASE_UNKNOWN 0
94 #define UCHCOM_BPS_MOD_BASE 20000000
95 #define UCHCOM_BPS_MOD_BASE_OFS 1100
97 #define UCHCOM_DTR_MASK 0x20
98 #define UCHCOM_RTS_MASK 0x40
100 #define UCHCOM_BRK1_MASK 0x01
101 #define UCHCOM_BRK2_MASK 0x40
103 #define UCHCOM_LCR1_MASK 0xAF
104 #define UCHCOM_LCR2_MASK 0x07
105 #define UCHCOM_LCR1_PARENB 0x80
106 #define UCHCOM_LCR2_PAREVEN 0x07
107 #define UCHCOM_LCR2_PARODD 0x06
108 #define UCHCOM_LCR2_PARMARK 0x05
109 #define UCHCOM_LCR2_PARSPACE 0x04
111 #define UCHCOM_INTR_STAT1 0x02
112 #define UCHCOM_INTR_STAT2 0x03
113 #define UCHCOM_INTR_LEAST 4
115 #define UCHCOMIBUFSIZE 256
116 #define UCHCOMOBUFSIZE 256
120 struct ucom_softc sc_ucom;
122 int sc_intr_endpoint;
124 usbd_pipe_handle sc_intr_pipe;
136 struct uchcom_endpoints
144 struct uchcom_divider
146 uint8_t dv_prescaler;
151 struct uchcom_divider_record
155 uint32_t dvr_base_clock;
156 struct uchcom_divider dvr_divider;
159 static const struct uchcom_divider_record dividers[] =
161 { 307200, 307200, UCHCOM_BASE_UNKNOWN, { 7, 0xD9, 0 } },
162 { 921600, 921600, UCHCOM_BASE_UNKNOWN, { 7, 0xF3, 0 } },
163 { 2999999, 23530, 6000000, { 3, 0, 0 } },
164 { 23529, 2942, 750000, { 2, 0, 0 } },
165 { 2941, 368, 93750, { 1, 0, 0 } },
166 { 367, 1, 11719, { 0, 0, 0 } },
168 #define NUM_DIVIDERS (sizeof (dividers) / sizeof (dividers[0]))
170 static void uchcom_get_status(void *, int, u_char *, u_char *);
171 static void uchcom_set(void *, int, int, int);
172 static int uchcom_param(void *, int, struct termios *);
173 static int uchcom_open(void *, int);
174 static void uchcom_close(void *, int);
175 static void uchcom_intr(usbd_xfer_handle, usbd_private_handle,
178 static int set_config(struct uchcom_softc *);
179 static int find_ifaces(struct uchcom_softc *, usbd_interface_handle *);
180 static int find_endpoints(struct uchcom_softc *,
181 struct uchcom_endpoints *);
182 static void close_intr_pipe(struct uchcom_softc *);
184 static device_probe_t uchcom_match;
185 static device_attach_t uchcom_attach;
186 static device_detach_t uchcom_detach;
188 static device_method_t uchcom_methods[] = {
189 DEVMETHOD(device_probe, uchcom_match),
190 DEVMETHOD(device_attach, uchcom_attach),
191 DEVMETHOD(device_detach, uchcom_detach),
195 static driver_t uchcom_driver = {
198 sizeof (struct uchcom_softc)
201 DRIVER_MODULE(uchcom, uhub, uchcom_driver, ucom_devclass, usbd_driver_load, NULL);
202 MODULE_DEPEND(uchcom, usb, 1, 1, 1);
203 MODULE_DEPEND(uchcom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
204 MODULE_VERSION(uchcom, 1);
206 struct ucom_callback uchcom_callback = {
207 .ucom_get_status = uchcom_get_status,
208 .ucom_set = uchcom_set,
209 .ucom_param = uchcom_param,
211 .ucom_open = uchcom_open,
212 .ucom_close = uchcom_close,
217 static const struct usb_devno uchcom_devs[] = {
218 { USB_DEVICE(0x4348, 0x5523) }, /* QinHeng Electronics CH341/340 */
220 #define uchcom_lookup(v, p) usb_lookup(uchcom_devs, v, p)
222 /* ----------------------------------------------------------------------
223 * driver entry points
227 uchcom_match(device_t self)
229 struct usb_attach_arg *uaa = device_get_ivars(self);
231 if (uaa->iface != NULL)
234 return (uchcom_lookup(uaa->vendor, uaa->product) != NULL ?
235 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
239 uchcom_attach(device_t self)
241 struct uchcom_softc *sc = device_get_softc(self);
242 struct usb_attach_arg *uaa = device_get_ivars(self);
243 struct ucom_softc *ucom = &sc->sc_ucom;
244 usbd_device_handle dev = uaa->device;
245 struct uchcom_endpoints endpoints;
247 bzero(sc, sizeof (struct uchcom_softc));
251 sc->sc_dtr = sc->sc_rts = -1;
252 sc->sc_lsr = sc->sc_msr = 0;
254 DPRINTF(("\n\nuchcom attach: sc=%p\n", sc));
259 switch (uaa->release) {
260 case UCHCOM_REV_CH340:
261 device_printf(ucom->sc_dev, "CH340\n");
264 device_printf(ucom->sc_dev, "CH341\n");
268 if (find_ifaces(sc, &ucom->sc_iface))
271 if (find_endpoints(sc, &endpoints))
274 sc->sc_intr_endpoint = endpoints.ep_intr;
275 sc->sc_intr_size = endpoints.ep_intr_size;
277 /* setup ucom layer */
278 ucom->sc_parent = sc;
279 ucom->sc_portno = UCOM_UNK_PORTNO;
280 ucom->sc_bulkin_no = endpoints.ep_bulkin;
281 ucom->sc_bulkout_no = endpoints.ep_bulkout;
282 ucom->sc_ibufsize = UCHCOMIBUFSIZE;
283 ucom->sc_obufsize = UCHCOMOBUFSIZE;
284 ucom->sc_ibufsizepad = UCHCOMIBUFSIZE;
285 ucom->sc_opkthdrlen = 0;
286 ucom->sc_callback = &uchcom_callback;
288 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, ucom->sc_udev,
290 ucom_attach(&sc->sc_ucom);
300 uchcom_detach(device_t self)
302 struct uchcom_softc *sc = device_get_softc(self);
305 DPRINTF(("uchcom_detach: sc=%p flags=%d\n", sc, flags));
308 sc->sc_ucom.sc_dying = 1;
309 rv = ucom_detach(&sc->sc_ucom);
310 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_ucom.sc_udev,
318 uchcom_activate(struct device *self, enum devact act)
320 struct uchcom_softc *sc = (struct uchcom_softc *)self;
327 case DVACT_DEACTIVATE:
328 uchcom_close_intr_pipe(sc);
330 if (sc->sc_subdev != NULL)
331 rv = config_deactivate(sc->sc_subdev);
339 set_config(struct uchcom_softc *sc)
343 err = usbd_set_config_index(sc->sc_ucom.sc_udev,
344 UCHCOM_CONFIG_INDEX, 1);
346 device_printf(sc->sc_ucom.sc_dev, "failed to set "
347 "configuration: %s\n", usbd_errstr(err));
355 find_ifaces(struct uchcom_softc *sc, usbd_interface_handle *riface)
359 err = usbd_device2interface_handle(sc->sc_ucom.sc_udev,
360 UCHCOM_IFACE_INDEX, riface);
362 device_printf(sc->sc_ucom.sc_dev, "failed to get interface: "
363 "%s\n", usbd_errstr(err));
371 find_endpoints(struct uchcom_softc *sc,
372 struct uchcom_endpoints *endpoints)
374 int i, bin=-1, bout=-1, intr=-1, isize=0;
375 usb_interface_descriptor_t *id;
376 usb_endpoint_descriptor_t *ed;
378 id = usbd_get_interface_descriptor(sc->sc_ucom.sc_iface);
380 for (i = 0; i < id->bNumEndpoints; i++) {
381 ed = usbd_interface2endpoint_descriptor(sc->sc_ucom.sc_iface,
384 device_printf(sc->sc_ucom.sc_dev,
385 "no endpoint descriptor for %d\n", i);
389 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
390 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
391 intr = ed->bEndpointAddress;
392 isize = UGETW(ed->wMaxPacketSize);
393 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
394 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
395 bin = ed->bEndpointAddress;
396 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
397 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
398 bout = ed->bEndpointAddress;
402 if (intr == -1 || bin == -1 || bout == -1) {
404 device_printf(sc->sc_ucom.sc_dev,
405 "no interrupt end point\n");
408 device_printf(sc->sc_ucom.sc_dev,
409 "no data bulk in end point\n");
412 device_printf(sc->sc_ucom.sc_dev,
413 "no data bulk out end point\n");
417 if (isize < UCHCOM_INTR_LEAST) {
418 device_printf(sc->sc_ucom.sc_dev, "intr pipe is too short\n");
422 DPRINTF(("%s: bulkin=%d, bulkout=%d, intr=%d, isize=%d\n",
423 device_get_nameunit(sc->sc_ucom.sc_dev), bin, bout, intr,
426 endpoints->ep_intr = intr;
427 endpoints->ep_intr_size = isize;
428 endpoints->ep_bulkin = bin;
429 endpoints->ep_bulkout = bout;
435 /* ----------------------------------------------------------------------
439 static __inline usbd_status
440 generic_control_out(struct uchcom_softc *sc, uint8_t reqno,
441 uint16_t value, uint16_t index)
443 usb_device_request_t req;
445 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
446 req.bRequest = reqno;
447 USETW(req.wValue, value);
448 USETW(req.wIndex, index);
449 USETW(req.wLength, 0);
451 return usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
454 static __inline usbd_status
455 generic_control_in(struct uchcom_softc *sc, uint8_t reqno,
456 uint16_t value, uint16_t index, void *buf, int buflen, int *actlen)
458 usb_device_request_t req;
460 req.bmRequestType = UT_READ_VENDOR_DEVICE;
461 req.bRequest = reqno;
462 USETW(req.wValue, value);
463 USETW(req.wIndex, index);
464 USETW(req.wLength, (uint16_t)buflen);
466 return usbd_do_request_flags(sc->sc_ucom.sc_udev, &req, buf,
467 USBD_SHORT_XFER_OK, actlen,
468 USBD_DEFAULT_TIMEOUT);
471 static __inline usbd_status
472 write_reg(struct uchcom_softc *sc,
473 uint8_t reg1, uint8_t val1, uint8_t reg2, uint8_t val2)
475 DPRINTF(("uchcom: write reg 0x%02X<-0x%02X, 0x%02X<-0x%02X\n",
476 (unsigned)reg1, (unsigned)val1,
477 (unsigned)reg2, (unsigned)val2));
478 return generic_control_out(
479 sc, UCHCOM_REQ_WRITE_REG,
480 reg1|((uint16_t)reg2<<8), val1|((uint16_t)val2<<8));
483 static __inline usbd_status
484 read_reg(struct uchcom_softc *sc,
485 uint8_t reg1, uint8_t *rval1, uint8_t reg2, uint8_t *rval2)
487 uint8_t buf[UCHCOM_INPUT_BUF_SIZE];
491 err = generic_control_in(
492 sc, UCHCOM_REQ_READ_REG,
493 reg1|((uint16_t)reg2<<8), 0, buf, sizeof buf, &actin);
497 DPRINTF(("uchcom: read reg 0x%02X->0x%02X, 0x%02X->0x%02X\n",
498 (unsigned)reg1, (unsigned)buf[0],
499 (unsigned)reg2, (unsigned)buf[1]));
501 if (rval1) *rval1 = buf[0];
502 if (rval2) *rval2 = buf[1];
504 return USBD_NORMAL_COMPLETION;
507 static __inline usbd_status
508 get_version(struct uchcom_softc *sc, uint8_t *rver)
510 uint8_t buf[UCHCOM_INPUT_BUF_SIZE];
514 err = generic_control_in(
515 sc, UCHCOM_REQ_GET_VERSION, 0, 0, buf, sizeof buf, &actin);
519 if (rver) *rver = buf[0];
521 return USBD_NORMAL_COMPLETION;
524 static __inline usbd_status
525 read_status(struct uchcom_softc *sc, uint8_t *rval)
527 return read_reg(sc, UCHCOM_REG_STAT1, rval, UCHCOM_REG_STAT2, NULL);
530 static __inline usbd_status
531 set_dtrrts_10(struct uchcom_softc *sc, uint8_t val)
533 return write_reg(sc, UCHCOM_REG_STAT1, val, UCHCOM_REG_STAT1, val);
536 static __inline usbd_status
537 set_dtrrts_20(struct uchcom_softc *sc, uint8_t val)
539 return generic_control_out(sc, UCHCOM_REQ_SET_DTRRTS, val, 0);
543 /* ----------------------------------------------------------------------
548 update_version(struct uchcom_softc *sc)
552 err = get_version(sc, &sc->sc_version);
554 device_printf(sc->sc_ucom.sc_dev, "cannot get version: %s\n",
563 convert_status(struct uchcom_softc *sc, uint8_t cur)
565 sc->sc_dtr = !(cur & UCHCOM_DTR_MASK);
566 sc->sc_rts = !(cur & UCHCOM_RTS_MASK);
569 sc->sc_msr = (cur << 4) | ((sc->sc_msr >> 4) ^ cur);
573 update_status(struct uchcom_softc *sc)
578 err = read_status(sc, &cur);
580 device_printf(sc->sc_ucom.sc_dev, "cannot update status: %s\n",
584 convert_status(sc, cur);
591 set_dtrrts(struct uchcom_softc *sc, int dtr, int rts)
596 if (dtr) val |= UCHCOM_DTR_MASK;
597 if (rts) val |= UCHCOM_RTS_MASK;
599 if (sc->sc_version < UCHCOM_VER_20)
600 err = set_dtrrts_10(sc, ~val);
602 err = set_dtrrts_20(sc, ~val);
605 device_printf(sc->sc_ucom.sc_dev, "cannot set DTR/RTS: %s\n",
614 set_break(struct uchcom_softc *sc, int onoff)
619 err = read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_BREAK2,
624 /* on - clear bits */
625 brk1 &= ~UCHCOM_BRK1_MASK;
626 brk2 &= ~UCHCOM_BRK2_MASK;
629 brk1 |= UCHCOM_BRK1_MASK;
630 brk2 |= UCHCOM_BRK2_MASK;
632 err = write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_BREAK2,
641 calc_divider_settings(struct uchcom_divider *dp, uint32_t rate)
644 const struct uchcom_divider_record *rp;
645 uint32_t div, rem, mod;
648 for (i=0; i<NUM_DIVIDERS; i++) {
649 if (dividers[i].dvr_high >= rate &&
650 dividers[i].dvr_low <= rate) {
658 dp->dv_prescaler = rp->dvr_divider.dv_prescaler;
659 if (rp->dvr_base_clock == UCHCOM_BASE_UNKNOWN)
660 dp->dv_div = rp->dvr_divider.dv_div;
662 div = rp->dvr_base_clock / rate;
663 rem = rp->dvr_base_clock % rate;
664 if (div==0 || div>=0xFF)
666 if ((rem<<1) >= rate)
668 dp->dv_div = (uint8_t)-div;
671 mod = UCHCOM_BPS_MOD_BASE/rate + UCHCOM_BPS_MOD_BASE_OFS;
674 dp->dv_mod = mod / 0x100;
680 set_dte_rate(struct uchcom_softc *sc, uint32_t rate)
683 struct uchcom_divider dv;
685 if (calc_divider_settings(&dv, rate))
688 if ((err = write_reg(sc,
689 UCHCOM_REG_BPS_PRE, dv.dv_prescaler,
690 UCHCOM_REG_BPS_DIV, dv.dv_div)) ||
692 UCHCOM_REG_BPS_MOD, dv.dv_mod,
693 UCHCOM_REG_BPS_PAD, 0))) {
694 device_printf(sc->sc_ucom.sc_dev, "cannot set DTE rate: %s\n",
703 set_line_control(struct uchcom_softc *sc, tcflag_t cflag)
706 uint8_t lcr1 = 0, lcr2 = 0;
708 err = read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2);
710 device_printf(sc->sc_ucom.sc_dev, "cannot get LCR: %s\n",
715 lcr1 &= ~UCHCOM_LCR1_MASK;
716 lcr2 &= ~UCHCOM_LCR2_MASK;
719 * XXX: it is difficult to handle the line control appropriately:
720 * - CS8, !CSTOPB and any parity mode seems ok, but
721 * - the chip doesn't have the function to calculate parity
723 * - it is unclear that the chip supports CS5,6 mode.
724 * - it is unclear how to handle stop bits.
727 switch (ISSET(cflag, CSIZE)) {
736 if (ISSET(cflag, PARENB)) {
737 lcr1 |= UCHCOM_LCR1_PARENB;
738 if (ISSET(cflag, PARODD))
739 lcr2 |= UCHCOM_LCR2_PARODD;
741 lcr2 |= UCHCOM_LCR2_PAREVEN;
744 err = write_reg(sc, UCHCOM_REG_LCR1, lcr1, UCHCOM_REG_LCR2,
747 device_printf(sc->sc_ucom.sc_dev, "cannot set LCR: %s\n",
756 clear_chip(struct uchcom_softc *sc)
760 DPRINTF(("%s: clear\n", sc->sc_dev.dv_xname));
761 err = generic_control_out(sc, UCHCOM_REQ_RESET, 0, 0);
763 device_printf(sc->sc_ucom.sc_dev, "cannot clear: %s\n",
772 reset_chip(struct uchcom_softc *sc)
775 uint8_t lcr1, lcr2, pre, div, mod;
776 uint16_t val=0, idx=0;
778 err = read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2);
782 err = read_reg(sc, UCHCOM_REG_BPS_PRE, &pre, UCHCOM_REG_BPS_DIV,
787 err = read_reg(sc, UCHCOM_REG_BPS_MOD, &mod, UCHCOM_REG_BPS_PAD,
792 val |= (uint16_t)(lcr1&0xF0) << 8;
794 val |= (uint16_t)(lcr2&0x0F) << 8;
798 idx |= (uint16_t)div << 8;
803 DPRINTF(("%s: reset v=0x%04X, i=0x%04X\n",
804 device_get_nameunit(sc->sc_ucom.sc_dev), val, idx));
806 err = generic_control_out(sc, UCHCOM_REQ_RESET, val, idx);
813 device_printf(sc->sc_ucom.sc_dev, "cannot reset: %s\n",
819 setup_comm(struct uchcom_softc *sc)
823 ret = update_version(sc);
827 ret = clear_chip(sc);
831 ret = set_dte_rate(sc, TTYDEF_SPEED);
835 ret = set_line_control(sc, CS8);
839 ret = update_status(sc);
843 ret = reset_chip(sc);
847 ret = set_dte_rate(sc, TTYDEF_SPEED); /* XXX */
851 sc->sc_dtr = sc->sc_rts = 1;
852 ret = set_dtrrts(sc, sc->sc_dtr, sc->sc_rts);
860 setup_intr_pipe(struct uchcom_softc *sc)
864 if (sc->sc_intr_endpoint != -1 && sc->sc_intr_pipe == NULL) {
865 sc->sc_intr_buf = kmalloc(sc->sc_intr_size, M_USBDEV, M_WAITOK);
866 err = usbd_open_pipe_intr(sc->sc_ucom.sc_iface,
867 sc->sc_intr_endpoint,
869 &sc->sc_intr_pipe, sc,
872 uchcom_intr, USBD_DEFAULT_INTERVAL);
874 device_printf(sc->sc_ucom.sc_dev, "cannot open "
875 "interrupt pipe: %s\n", usbd_errstr(err));
883 close_intr_pipe(struct uchcom_softc *sc)
887 if (sc->sc_ucom.sc_dying)
890 if (sc->sc_intr_pipe != NULL) {
891 err = usbd_abort_pipe(sc->sc_intr_pipe);
893 device_printf(sc->sc_ucom.sc_dev, "abort interrupt "
894 "pipe failed: %s\n", usbd_errstr(err));
895 err = usbd_close_pipe(sc->sc_intr_pipe);
897 device_printf(sc->sc_ucom.sc_dev, "close interrupt "
898 "pipe failed: %s\n", usbd_errstr(err));
899 kfree(sc->sc_intr_buf, M_USBDEV);
900 sc->sc_intr_pipe = NULL;
905 /* ----------------------------------------------------------------------
909 uchcom_get_status(void *arg, int portno, u_char *rlsr, u_char *rmsr)
911 struct uchcom_softc *sc = arg;
913 if (sc->sc_ucom.sc_dying)
921 uchcom_set(void *arg, int portno, int reg, int onoff)
923 struct uchcom_softc *sc = arg;
925 if (sc->sc_ucom.sc_dying)
930 sc->sc_dtr = !!onoff;
931 set_dtrrts(sc, sc->sc_dtr, sc->sc_rts);
934 sc->sc_rts = !!onoff;
935 set_dtrrts(sc, sc->sc_dtr, sc->sc_rts);
938 set_break(sc, onoff);
944 uchcom_param(void *arg, int portno, struct termios *t)
946 struct uchcom_softc *sc = arg;
949 if (sc->sc_ucom.sc_dying)
952 ret = set_line_control(sc, t->c_cflag);
956 ret = set_dte_rate(sc, t->c_ospeed);
964 uchcom_open(void *arg, int portno)
967 struct uchcom_softc *sc = arg;
969 if (sc->sc_ucom.sc_dying)
972 ret = setup_intr_pipe(sc);
976 ret = setup_comm(sc);
984 uchcom_close(void *arg, int portno)
986 struct uchcom_softc *sc = arg;
988 if (sc->sc_ucom.sc_dying)
995 /* ----------------------------------------------------------------------
996 * callback when the modem status is changed.
999 uchcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
1002 struct uchcom_softc *sc = priv;
1003 u_char *buf = sc->sc_intr_buf;
1005 if (sc->sc_ucom.sc_dying)
1008 if (status != USBD_NORMAL_COMPLETION) {
1009 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1012 DPRINTF(("%s: abnormal status: %s\n",
1013 device_get_nameunit(sc->sc_ucom.sc_dev),
1014 usbd_errstr(status)));
1015 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
1018 DPRINTF(("%s: intr: 0x%02X 0x%02X 0x%02X 0x%02X "
1019 "0x%02X 0x%02X 0x%02X 0x%02X\n",
1020 device_get_nameunit(sc->sc_ucom.sc_dev),
1021 (unsigned)buf[0], (unsigned)buf[1],
1022 (unsigned)buf[2], (unsigned)buf[3],
1023 (unsigned)buf[4], (unsigned)buf[5],
1024 (unsigned)buf[6], (unsigned)buf[7]));
1026 convert_status(sc, buf[UCHCOM_INTR_STAT1]);
1027 ucom_status_change(&sc->sc_ucom);