1 /* $NetBSD: uchcom.c,v 1.8 2009/09/23 19:07:19 plunky 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.
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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: uchcom.c,v 1.8 2009/09/23 19:07:19 plunky Exp $");
36 * driver for WinChipHead CH341/340, the worst USB-serial chip in the world.
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/ioctl.h>
47 #include <sys/select.h>
49 #include <sys/device.h>
51 #include <sys/workqueue.h>
53 #include <dev/usb/usb.h>
54 #include <dev/usb/usbcdc.h>
56 #include <dev/usb/usbdi.h>
57 #include <dev/usb/usbdi_util.h>
58 #include <dev/usb/usbdevs.h>
59 #include <dev/usb/usb_quirks.h>
61 #include <dev/usb/ucomvar.h>
64 #define DPRINTFN(n, x) if (uchcomdebug > (n)) logprintf x
67 #define DPRINTFN(n, x)
69 #define DPRINTF(x) DPRINTFN(0, x)
71 #define UCHCOM_IFACE_INDEX 0
72 #define UCHCOM_CONFIG_INDEX 0
74 #define UCHCOM_REV_CH340 0x0250
75 #define UCHCOM_INPUT_BUF_SIZE 8
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
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_BPS_MOD 0x14
88 #define UCHCOM_REG_BPS_PAD 0x0F
89 #define UCHCOM_REG_BREAK1 0x05
90 #define UCHCOM_REG_BREAK2 0x18
91 #define UCHCOM_REG_LCR1 0x18
92 #define UCHCOM_REG_LCR2 0x25
94 #define UCHCOM_VER_20 0x20
96 #define UCHCOM_BASE_UNKNOWN 0
97 #define UCHCOM_BPS_MOD_BASE 20000000
98 #define UCHCOM_BPS_MOD_BASE_OFS 1100
100 #define UCHCOM_DTR_MASK 0x20
101 #define UCHCOM_RTS_MASK 0x40
103 #define UCHCOM_BRK1_MASK 0x01
104 #define UCHCOM_BRK2_MASK 0x40
106 #define UCHCOM_LCR1_MASK 0xAF
107 #define UCHCOM_LCR2_MASK 0x07
108 #define UCHCOM_LCR1_PARENB 0x80
109 #define UCHCOM_LCR2_PAREVEN 0x07
110 #define UCHCOM_LCR2_PARODD 0x06
111 #define UCHCOM_LCR2_PARMARK 0x05
112 #define UCHCOM_LCR2_PARSPACE 0x04
114 #define UCHCOM_INTR_STAT1 0x02
115 #define UCHCOM_INTR_STAT2 0x03
116 #define UCHCOM_INTR_LEAST 4
118 #define UCHCOMIBUFSIZE 256
119 #define UCHCOMOBUFSIZE 256
123 USBBASEDEVICE sc_dev
;
124 usbd_device_handle sc_udev
;
125 device_ptr_t sc_subdev
;
126 usbd_interface_handle sc_iface
;
129 int sc_intr_endpoint
;
131 usbd_pipe_handle sc_intr_pipe
;
143 struct uchcom_endpoints
151 struct uchcom_divider
153 uint8_t dv_prescaler
;
158 struct uchcom_divider_record
162 uint32_t dvr_base_clock
;
163 struct uchcom_divider dvr_divider
;
166 static const struct uchcom_divider_record dividers
[] =
168 { 307200, 307200, UCHCOM_BASE_UNKNOWN
, { 7, 0xD9, 0 } },
169 { 921600, 921600, UCHCOM_BASE_UNKNOWN
, { 7, 0xF3, 0 } },
170 { 2999999, 23530, 6000000, { 3, 0, 0 } },
171 { 23529, 2942, 750000, { 2, 0, 0 } },
172 { 2941, 368, 93750, { 1, 0, 0 } },
173 { 367, 1, 11719, { 0, 0, 0 } },
175 #define NUM_DIVIDERS (sizeof (dividers) / sizeof (dividers[0]))
177 static const struct usb_devno uchcom_devs
[] = {
178 { USB_VENDOR_WINCHIPHEAD
, USB_PRODUCT_WINCHIPHEAD_CH341SER
},
179 { USB_VENDOR_WINCHIPHEAD2
, USB_PRODUCT_WINCHIPHEAD2_CH341
},
181 #define uchcom_lookup(v, p) usb_lookup(uchcom_devs, v, p)
183 Static
void uchcom_get_status(void *, int, u_char
*, u_char
*);
184 Static
void uchcom_set(void *, int, int, int);
185 Static
int uchcom_param(void *, int, struct termios
*);
186 Static
int uchcom_open(void *, int);
187 Static
void uchcom_close(void *, int);
188 Static
void uchcom_intr(usbd_xfer_handle
, usbd_private_handle
,
191 static int set_config(struct uchcom_softc
*);
192 static int find_ifaces(struct uchcom_softc
*, usbd_interface_handle
*);
193 static int find_endpoints(struct uchcom_softc
*,
194 struct uchcom_endpoints
*);
195 static void close_intr_pipe(struct uchcom_softc
*);
198 struct ucom_methods uchcom_methods
= {
199 .ucom_get_status
= uchcom_get_status
,
200 .ucom_set
= uchcom_set
,
201 .ucom_param
= uchcom_param
,
203 .ucom_open
= uchcom_open
,
204 .ucom_close
= uchcom_close
,
209 int uchcom_match(device_t
, cfdata_t
, void *);
210 void uchcom_attach(device_t
, device_t
, void *);
211 void uchcom_childdet(device_t
, device_t
);
212 int uchcom_detach(device_t
, int);
213 int uchcom_activate(device_t
, enum devact
);
215 extern struct cfdriver uchcom_cd
;
217 CFATTACH_DECL2_NEW(uchcom
,
218 sizeof(struct uchcom_softc
),
226 /* ----------------------------------------------------------------------
227 * driver entry points
232 USB_MATCH_START(uchcom
, uaa
);
234 return (uchcom_lookup(uaa
->vendor
, uaa
->product
) != NULL
?
235 UMATCH_VENDOR_PRODUCT
: UMATCH_NONE
);
240 USB_ATTACH_START(uchcom
, sc
, uaa
);
241 usbd_device_handle dev
= uaa
->device
;
243 struct uchcom_endpoints endpoints
;
244 struct ucom_attach_args uca
;
249 devinfop
= usbd_devinfo_alloc(dev
, 0);
250 aprint_normal_dev(self
, "%s\n", devinfop
);
251 usbd_devinfo_free(devinfop
);
256 sc
->sc_dtr
= sc
->sc_rts
= -1;
257 sc
->sc_lsr
= sc
->sc_msr
= 0;
259 DPRINTF(("\n\nuchcom attach: sc=%p\n", sc
));
264 switch (uaa
->release
) {
265 case UCHCOM_REV_CH340
:
266 aprint_normal_dev(self
, "CH340 detected\n");
269 aprint_normal_dev(self
, "CH341 detected\n");
273 if (find_ifaces(sc
, &sc
->sc_iface
))
276 if (find_endpoints(sc
, &endpoints
))
279 sc
->sc_intr_endpoint
= endpoints
.ep_intr
;
280 sc
->sc_intr_size
= endpoints
.ep_intr_size
;
282 /* setup ucom layer */
283 uca
.portno
= UCOM_UNK_PORTNO
;
284 uca
.bulkin
= endpoints
.ep_bulkin
;
285 uca
.bulkout
= endpoints
.ep_bulkout
;
286 uca
.ibufsize
= UCHCOMIBUFSIZE
;
287 uca
.obufsize
= UCHCOMOBUFSIZE
;
288 uca
.ibufsizepad
= UCHCOMIBUFSIZE
;
291 uca
.iface
= sc
->sc_iface
;
292 uca
.methods
= &uchcom_methods
;
296 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH
, sc
->sc_udev
,
299 sc
->sc_subdev
= config_found_sm_loc(self
, "ucombus", NULL
, &uca
,
300 ucomprint
, ucomsubmatch
);
302 USB_ATTACH_SUCCESS_RETURN
;
306 USB_ATTACH_ERROR_RETURN
;
310 uchcom_childdet(device_t self
, device_t child
)
312 struct uchcom_softc
*sc
= device_private(self
);
314 KASSERT(sc
->sc_subdev
== child
);
315 sc
->sc_subdev
= NULL
;
320 USB_DETACH_START(uchcom
, sc
);
323 DPRINTF(("uchcom_detach: sc=%p flags=%d\n", sc
, flags
));
329 if (sc
->sc_subdev
!= NULL
)
330 rv
= config_detach(sc
->sc_subdev
, flags
);
332 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH
, sc
->sc_udev
,
339 uchcom_activate(device_t self
, enum devact act
)
341 struct uchcom_softc
*sc
= device_private(self
);
344 case DVACT_DEACTIVATE
:
354 set_config(struct uchcom_softc
*sc
)
358 err
= usbd_set_config_index(sc
->sc_udev
, UCHCOM_CONFIG_INDEX
, 1);
360 aprint_error_dev(sc
->sc_dev
,
361 "failed to set configuration: %s\n", usbd_errstr(err
));
369 find_ifaces(struct uchcom_softc
*sc
, usbd_interface_handle
*riface
)
373 err
= usbd_device2interface_handle(sc
->sc_udev
, UCHCOM_IFACE_INDEX
,
376 aprint_error("\n%s: failed to get interface: %s\n",
377 USBDEVNAME(sc
->sc_dev
), usbd_errstr(err
));
385 find_endpoints(struct uchcom_softc
*sc
, struct uchcom_endpoints
*endpoints
)
387 int i
, bin
=-1, bout
=-1, intr
=-1, isize
=0;
388 usb_interface_descriptor_t
*id
;
389 usb_endpoint_descriptor_t
*ed
;
391 id
= usbd_get_interface_descriptor(sc
->sc_iface
);
393 for (i
= 0; i
< id
->bNumEndpoints
; i
++) {
394 ed
= usbd_interface2endpoint_descriptor(sc
->sc_iface
, i
);
396 aprint_error_dev(sc
->sc_dev
,
397 "no endpoint descriptor for %d\n", i
);
401 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
402 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_INTERRUPT
) {
403 intr
= ed
->bEndpointAddress
;
404 isize
= UGETW(ed
->wMaxPacketSize
);
405 } else if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
406 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
407 bin
= ed
->bEndpointAddress
;
408 } else if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_OUT
&&
409 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
410 bout
= ed
->bEndpointAddress
;
414 if (intr
== -1 || bin
== -1 || bout
== -1) {
416 aprint_error_dev(sc
->sc_dev
,
417 "no interrupt end point\n");
420 aprint_error_dev(sc
->sc_dev
,
421 "no data bulk in end point\n");
424 aprint_error_dev(sc
->sc_dev
,
425 "no data bulk out end point\n");
429 if (isize
< UCHCOM_INTR_LEAST
) {
430 aprint_error_dev(sc
->sc_dev
, "intr pipe is too short\n");
434 DPRINTF(("%s: bulkin=%d, bulkout=%d, intr=%d, isize=%d\n",
435 USBDEVNAME(sc
->sc_dev
), bin
, bout
, intr
, isize
));
437 endpoints
->ep_intr
= intr
;
438 endpoints
->ep_intr_size
= isize
;
439 endpoints
->ep_bulkin
= bin
;
440 endpoints
->ep_bulkout
= bout
;
446 /* ----------------------------------------------------------------------
450 static __inline usbd_status
451 generic_control_out(struct uchcom_softc
*sc
, uint8_t reqno
,
452 uint16_t value
, uint16_t index
)
454 usb_device_request_t req
;
456 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
457 req
.bRequest
= reqno
;
458 USETW(req
.wValue
, value
);
459 USETW(req
.wIndex
, index
);
460 USETW(req
.wLength
, 0);
462 return usbd_do_request(sc
->sc_udev
, &req
, 0);
465 static __inline usbd_status
466 generic_control_in(struct uchcom_softc
*sc
, uint8_t reqno
,
467 uint16_t value
, uint16_t index
, void *buf
, int buflen
,
470 usb_device_request_t req
;
472 req
.bmRequestType
= UT_READ_VENDOR_DEVICE
;
473 req
.bRequest
= reqno
;
474 USETW(req
.wValue
, value
);
475 USETW(req
.wIndex
, index
);
476 USETW(req
.wLength
, (uint16_t)buflen
);
478 return usbd_do_request_flags(sc
->sc_udev
, &req
, buf
,
479 USBD_SHORT_XFER_OK
, actlen
,
480 USBD_DEFAULT_TIMEOUT
);
483 static __inline usbd_status
484 write_reg(struct uchcom_softc
*sc
,
485 uint8_t reg1
, uint8_t val1
, uint8_t reg2
, uint8_t val2
)
487 DPRINTF(("uchcom: write reg 0x%02X<-0x%02X, 0x%02X<-0x%02X\n",
488 (unsigned)reg1
, (unsigned)val1
,
489 (unsigned)reg2
, (unsigned)val2
));
490 return generic_control_out(
491 sc
, UCHCOM_REQ_WRITE_REG
,
492 reg1
|((uint16_t)reg2
<<8), val1
|((uint16_t)val2
<<8));
495 static __inline usbd_status
496 read_reg(struct uchcom_softc
*sc
,
497 uint8_t reg1
, uint8_t *rval1
, uint8_t reg2
, uint8_t *rval2
)
499 uint8_t buf
[UCHCOM_INPUT_BUF_SIZE
];
503 err
= generic_control_in(
504 sc
, UCHCOM_REQ_READ_REG
,
505 reg1
|((uint16_t)reg2
<<8), 0, buf
, sizeof buf
, &actin
);
509 DPRINTF(("uchcom: read reg 0x%02X->0x%02X, 0x%02X->0x%02X\n",
510 (unsigned)reg1
, (unsigned)buf
[0],
511 (unsigned)reg2
, (unsigned)buf
[1]));
513 if (rval1
) *rval1
= buf
[0];
514 if (rval2
) *rval2
= buf
[1];
516 return USBD_NORMAL_COMPLETION
;
519 static __inline usbd_status
520 get_version(struct uchcom_softc
*sc
, uint8_t *rver
)
522 uint8_t buf
[UCHCOM_INPUT_BUF_SIZE
];
526 err
= generic_control_in(
527 sc
, UCHCOM_REQ_GET_VERSION
, 0, 0, buf
, sizeof buf
, &actin
);
531 if (rver
) *rver
= buf
[0];
533 return USBD_NORMAL_COMPLETION
;
536 static __inline usbd_status
537 get_status(struct uchcom_softc
*sc
, uint8_t *rval
)
539 return read_reg(sc
, UCHCOM_REG_STAT1
, rval
, UCHCOM_REG_STAT2
, NULL
);
542 static __inline usbd_status
543 set_dtrrts_10(struct uchcom_softc
*sc
, uint8_t val
)
545 return write_reg(sc
, UCHCOM_REG_STAT1
, val
, UCHCOM_REG_STAT1
, val
);
548 static __inline usbd_status
549 set_dtrrts_20(struct uchcom_softc
*sc
, uint8_t val
)
551 return generic_control_out(sc
, UCHCOM_REQ_SET_DTRRTS
, val
, 0);
555 /* ----------------------------------------------------------------------
560 update_version(struct uchcom_softc
*sc
)
564 err
= get_version(sc
, &sc
->sc_version
);
566 aprint_error_dev(sc
->sc_dev
, "cannot get version: %s\n",
575 convert_status(struct uchcom_softc
*sc
, uint8_t cur
)
577 sc
->sc_dtr
= !(cur
& UCHCOM_DTR_MASK
);
578 sc
->sc_rts
= !(cur
& UCHCOM_RTS_MASK
);
581 sc
->sc_msr
= (cur
<< 4) | ((sc
->sc_msr
>> 4) ^ cur
);
585 update_status(struct uchcom_softc
*sc
)
590 err
= get_status(sc
, &cur
);
592 aprint_error_dev(sc
->sc_dev
,
593 "cannot update status: %s\n", usbd_errstr(err
));
596 convert_status(sc
, cur
);
603 set_dtrrts(struct uchcom_softc
*sc
, int dtr
, int rts
)
608 if (dtr
) val
|= UCHCOM_DTR_MASK
;
609 if (rts
) val
|= UCHCOM_RTS_MASK
;
611 if (sc
->sc_version
< UCHCOM_VER_20
)
612 err
= set_dtrrts_10(sc
, ~val
);
614 err
= set_dtrrts_20(sc
, ~val
);
617 aprint_error_dev(sc
->sc_dev
, "cannot set DTR/RTS: %s\n",
626 set_break(struct uchcom_softc
*sc
, int onoff
)
631 err
= read_reg(sc
, UCHCOM_REG_BREAK1
, &brk1
, UCHCOM_REG_BREAK2
, &brk2
);
635 /* on - clear bits */
636 brk1
&= ~UCHCOM_BRK1_MASK
;
637 brk2
&= ~UCHCOM_BRK2_MASK
;
640 brk1
|= UCHCOM_BRK1_MASK
;
641 brk2
|= UCHCOM_BRK2_MASK
;
643 err
= write_reg(sc
, UCHCOM_REG_BREAK1
, brk1
, UCHCOM_REG_BREAK2
, brk2
);
651 calc_divider_settings(struct uchcom_divider
*dp
, uint32_t rate
)
654 const struct uchcom_divider_record
*rp
;
655 uint32_t div
, rem
, mod
;
658 for (i
=0; i
<NUM_DIVIDERS
; i
++) {
659 if (dividers
[i
].dvr_high
>= rate
&&
660 dividers
[i
].dvr_low
<= rate
) {
668 dp
->dv_prescaler
= rp
->dvr_divider
.dv_prescaler
;
669 if (rp
->dvr_base_clock
== UCHCOM_BASE_UNKNOWN
)
670 dp
->dv_div
= rp
->dvr_divider
.dv_div
;
672 div
= rp
->dvr_base_clock
/ rate
;
673 rem
= rp
->dvr_base_clock
% rate
;
674 if (div
==0 || div
>=0xFF)
676 if ((rem
<<1) >= rate
)
678 dp
->dv_div
= (uint8_t)-div
;
681 mod
= UCHCOM_BPS_MOD_BASE
/rate
+ UCHCOM_BPS_MOD_BASE_OFS
;
684 dp
->dv_mod
= mod
/ 0x100;
690 set_dte_rate(struct uchcom_softc
*sc
, uint32_t rate
)
693 struct uchcom_divider dv
;
695 if (calc_divider_settings(&dv
, rate
))
698 if ((err
= write_reg(sc
,
699 UCHCOM_REG_BPS_PRE
, dv
.dv_prescaler
,
700 UCHCOM_REG_BPS_DIV
, dv
.dv_div
)) ||
702 UCHCOM_REG_BPS_MOD
, dv
.dv_mod
,
703 UCHCOM_REG_BPS_PAD
, 0))) {
704 aprint_error_dev(sc
->sc_dev
, "cannot set DTE rate: %s\n",
713 set_line_control(struct uchcom_softc
*sc
, tcflag_t cflag
)
716 uint8_t lcr1val
= 0, lcr2val
= 0;
718 err
= read_reg(sc
, UCHCOM_REG_LCR1
, &lcr1val
, UCHCOM_REG_LCR2
, &lcr2val
);
720 aprint_error_dev(sc
->sc_dev
, "cannot get LCR: %s\n",
725 lcr1val
&= ~UCHCOM_LCR1_MASK
;
726 lcr2val
&= ~UCHCOM_LCR2_MASK
;
729 * XXX: it is difficult to handle the line control appropriately:
730 * - CS8, !CSTOPB and any parity mode seems ok, but
731 * - the chip doesn't have the function to calculate parity
733 * - it is unclear that the chip supports CS5,6 mode.
734 * - it is unclear how to handle stop bits.
737 switch (ISSET(cflag
, CSIZE
)) {
746 if (ISSET(cflag
, PARENB
)) {
747 lcr1val
|= UCHCOM_LCR1_PARENB
;
748 if (ISSET(cflag
, PARODD
))
749 lcr2val
|= UCHCOM_LCR2_PARODD
;
751 lcr2val
|= UCHCOM_LCR2_PAREVEN
;
754 err
= write_reg(sc
, UCHCOM_REG_LCR1
, lcr1val
, UCHCOM_REG_LCR2
, lcr2val
);
756 aprint_error_dev(sc
->sc_dev
, "cannot set LCR: %s\n",
765 clear_chip(struct uchcom_softc
*sc
)
769 DPRINTF(("%s: clear\n", USBDEVNAME(sc
->sc_dev
)));
770 err
= generic_control_out(sc
, UCHCOM_REQ_RESET
, 0, 0);
772 aprint_error_dev(sc
->sc_dev
, "cannot clear: %s\n",
781 reset_chip(struct uchcom_softc
*sc
)
784 uint8_t lcr1val
, lcr2val
, pre
, div
, mod
;
785 uint16_t val
=0, idx
=0;
787 err
= read_reg(sc
, UCHCOM_REG_LCR1
, &lcr1val
, UCHCOM_REG_LCR2
, &lcr2val
);
791 err
= read_reg(sc
, UCHCOM_REG_BPS_PRE
, &pre
, UCHCOM_REG_BPS_DIV
, &div
);
795 err
= read_reg(sc
, UCHCOM_REG_BPS_MOD
, &mod
, UCHCOM_REG_BPS_PAD
, NULL
);
799 val
|= (uint16_t)(lcr1val
&0xF0) << 8;
801 val
|= (uint16_t)(lcr2val
&0x0F) << 8;
805 idx
|= (uint16_t)div
<< 8;
810 DPRINTF(("%s: reset v=0x%04X, i=0x%04X\n",
811 USBDEVNAME(sc
->sc_dev
), val
, idx
));
813 err
= generic_control_out(sc
, UCHCOM_REQ_RESET
, val
, idx
);
820 printf("%s: cannot reset: %s\n",
821 USBDEVNAME(sc
->sc_dev
), usbd_errstr(err
));
826 setup_comm(struct uchcom_softc
*sc
)
830 ret
= update_version(sc
);
834 ret
= clear_chip(sc
);
838 ret
= set_dte_rate(sc
, TTYDEF_SPEED
);
842 ret
= set_line_control(sc
, CS8
);
846 ret
= update_status(sc
);
850 ret
= reset_chip(sc
);
854 ret
= set_dte_rate(sc
, TTYDEF_SPEED
); /* XXX */
858 sc
->sc_dtr
= sc
->sc_rts
= 1;
859 ret
= set_dtrrts(sc
, sc
->sc_dtr
, sc
->sc_rts
);
867 setup_intr_pipe(struct uchcom_softc
*sc
)
871 if (sc
->sc_intr_endpoint
!= -1 && sc
->sc_intr_pipe
== NULL
) {
872 sc
->sc_intr_buf
= malloc(sc
->sc_intr_size
, M_USBDEV
, M_WAITOK
);
873 err
= usbd_open_pipe_intr(sc
->sc_iface
,
874 sc
->sc_intr_endpoint
,
876 &sc
->sc_intr_pipe
, sc
,
879 uchcom_intr
, USBD_DEFAULT_INTERVAL
);
881 aprint_error_dev(sc
->sc_dev
,
882 "cannot open interrupt pipe: %s\n",
891 close_intr_pipe(struct uchcom_softc
*sc
)
898 if (sc
->sc_intr_pipe
!= NULL
) {
899 err
= usbd_abort_pipe(sc
->sc_intr_pipe
);
901 aprint_error_dev(sc
->sc_dev
,
902 "abort interrupt pipe failed: %s\n",
904 err
= usbd_close_pipe(sc
->sc_intr_pipe
);
906 aprint_error_dev(sc
->sc_dev
,
907 "close interrupt pipe failed: %s\n",
909 free(sc
->sc_intr_buf
, M_USBDEV
);
910 sc
->sc_intr_pipe
= NULL
;
915 /* ----------------------------------------------------------------------
919 uchcom_get_status(void *arg
, int portno
, u_char
*rlsr
, u_char
*rmsr
)
921 struct uchcom_softc
*sc
= arg
;
931 uchcom_set(void *arg
, int portno
, int reg
, int onoff
)
933 struct uchcom_softc
*sc
= arg
;
940 sc
->sc_dtr
= !!onoff
;
941 set_dtrrts(sc
, sc
->sc_dtr
, sc
->sc_rts
);
944 sc
->sc_rts
= !!onoff
;
945 set_dtrrts(sc
, sc
->sc_dtr
, sc
->sc_rts
);
948 set_break(sc
, onoff
);
954 uchcom_param(void *arg
, int portno
, struct termios
*t
)
956 struct uchcom_softc
*sc
= arg
;
962 ret
= set_line_control(sc
, t
->c_cflag
);
966 ret
= set_dte_rate(sc
, t
->c_ospeed
);
974 uchcom_open(void *arg
, int portno
)
977 struct uchcom_softc
*sc
= arg
;
982 ret
= setup_intr_pipe(sc
);
986 ret
= setup_comm(sc
);
994 uchcom_close(void *arg
, int portno
)
996 struct uchcom_softc
*sc
= arg
;
1001 close_intr_pipe(sc
);
1005 /* ----------------------------------------------------------------------
1006 * callback when the modem status is changed.
1009 uchcom_intr(usbd_xfer_handle xfer
, usbd_private_handle priv
,
1012 struct uchcom_softc
*sc
= priv
;
1013 u_char
*buf
= sc
->sc_intr_buf
;
1018 if (status
!= USBD_NORMAL_COMPLETION
) {
1019 if (status
== USBD_NOT_STARTED
|| status
== USBD_CANCELLED
)
1022 DPRINTF(("%s: abnormal status: %s\n",
1023 USBDEVNAME(sc
->sc_dev
), usbd_errstr(status
)));
1024 usbd_clear_endpoint_stall_async(sc
->sc_intr_pipe
);
1027 DPRINTF(("%s: intr: 0x%02X 0x%02X 0x%02X 0x%02X "
1028 "0x%02X 0x%02X 0x%02X 0x%02X\n",
1029 USBDEVNAME(sc
->sc_dev
),
1030 (unsigned)buf
[0], (unsigned)buf
[1],
1031 (unsigned)buf
[2], (unsigned)buf
[3],
1032 (unsigned)buf
[4], (unsigned)buf
[5],
1033 (unsigned)buf
[6], (unsigned)buf
[7]));
1035 convert_status(sc
, buf
[UCHCOM_INTR_STAT1
]);
1036 ucom_status_change(device_private(sc
->sc_subdev
));