1 /* $NetBSD: moscom.c,v 1.2 2009/09/23 19:07:19 plunky Exp $ */
2 /* $OpenBSD: moscom.c,v 1.11 2007/10/11 18:33:14 deraadt Exp $ */
5 * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/cdefs.h>
21 __KERNEL_RCSID(0, "$NetBSD: moscom.c,v 1.2 2009/09/23 19:07:19 plunky Exp $");
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/kernel.h>
28 #include <sys/device.h>
30 #include <dev/usb/usb.h>
31 #include <dev/usb/usbdi.h>
32 #include <dev/usb/usbdi_util.h>
33 #include <dev/usb/usbdevs.h>
35 #include <dev/usb/usbdevs.h>
36 #include <dev/usb/ucomvar.h>
38 #define MOSCOMBUFSZ 256
39 #define MOSCOM_CONFIG_NO 0
40 #define MOSCOM_IFACE_NO 0
42 #define MOSCOM_READ 0x0d
43 #define MOSCOM_WRITE 0x0e
44 #define MOSCOM_UART_REG 0x0300
45 #define MOSCOM_VEND_REG 0x0000
47 #define MOSCOM_TXBUF 0x00 /* Write */
48 #define MOSCOM_RXBUF 0x00 /* Read */
49 #define MOSCOM_INT 0x01
50 #define MOSCOM_FIFO 0x02 /* Write */
51 #define MOSCOM_ISR 0x02 /* Read */
52 #define MOSCOM_LCR 0x03
53 #define MOSCOM_MCR 0x04
54 #define MOSCOM_LSR 0x05
55 #define MOSCOM_MSR 0x06
56 #define MOSCOM_SCRATCH 0x07
57 #define MOSCOM_DIV_LO 0x08
58 #define MOSCOM_DIV_HI 0x09
59 #define MOSCOM_EFR 0x0a
60 #define MOSCOM_XON1 0x0b
61 #define MOSCOM_XON2 0x0c
62 #define MOSCOM_XOFF1 0x0d
63 #define MOSCOM_XOFF2 0x0e
65 #define MOSCOM_BAUDLO 0x00
66 #define MOSCOM_BAUDHI 0x01
68 #define MOSCOM_INT_RXEN 0x01
69 #define MOSCOM_INT_TXEN 0x02
70 #define MOSCOM_INT_RSEN 0x04
71 #define MOSCOM_INT_MDMEM 0x08
72 #define MOSCOM_INT_SLEEP 0x10
73 #define MOSCOM_INT_XOFF 0x20
74 #define MOSCOM_INT_RTS 0x40
76 #define MOSCOM_FIFO_EN 0x01
77 #define MOSCOM_FIFO_RXCLR 0x02
78 #define MOSCOM_FIFO_TXCLR 0x04
79 #define MOSCOM_FIFO_DMA_BLK 0x08
80 #define MOSCOM_FIFO_TXLVL_MASK 0x30
81 #define MOSCOM_FIFO_TXLVL_8 0x00
82 #define MOSCOM_FIFO_TXLVL_16 0x10
83 #define MOSCOM_FIFO_TXLVL_32 0x20
84 #define MOSCOM_FIFO_TXLVL_56 0x30
85 #define MOSCOM_FIFO_RXLVL_MASK 0xc0
86 #define MOSCOM_FIFO_RXLVL_8 0x00
87 #define MOSCOM_FIFO_RXLVL_16 0x40
88 #define MOSCOM_FIFO_RXLVL_56 0x80
89 #define MOSCOM_FIFO_RXLVL_80 0xc0
91 #define MOSCOM_ISR_MDM 0x00
92 #define MOSCOM_ISR_NONE 0x01
93 #define MOSCOM_ISR_TX 0x02
94 #define MOSCOM_ISR_RX 0x04
95 #define MOSCOM_ISR_LINE 0x06
96 #define MOSCOM_ISR_RXTIMEOUT 0x0c
97 #define MOSCOM_ISR_RX_XOFF 0x10
98 #define MOSCOM_ISR_RTSCTS 0x20
99 #define MOSCOM_ISR_FIFOEN 0xc0
101 #define MOSCOM_LCR_DBITS(x) (x - 5)
102 #define MOSCOM_LCR_STOP_BITS_1 0x00
103 #define MOSCOM_LCR_STOP_BITS_2 0x04 /* 2 if 6-8 bits/char or 1.5 if 5 */
104 #define MOSCOM_LCR_PARITY_NONE 0x00
105 #define MOSCOM_LCR_PARITY_ODD 0x08
106 #define MOSCOM_LCR_PARITY_EVEN 0x18
107 #define MOSCOM_LCR_BREAK 0x40
108 #define MOSCOM_LCR_DIVLATCH_EN 0x80
110 #define MOSCOM_MCR_DTR 0x01
111 #define MOSCOM_MCR_RTS 0x02
112 #define MOSCOM_MCR_LOOP 0x04
113 #define MOSCOM_MCR_INTEN 0x08
114 #define MOSCOM_MCR_LOOPBACK 0x10
115 #define MOSCOM_MCR_XONANY 0x20
116 #define MOSCOM_MCR_IRDA_EN 0x40
117 #define MOSCOM_MCR_BAUD_DIV4 0x80
119 #define MOSCOM_LSR_RXDATA 0x01
120 #define MOSCOM_LSR_RXOVER 0x02
121 #define MOSCOM_LSR_RXPAR_ERR 0x04
122 #define MOSCOM_LSR_RXFRM_ERR 0x08
123 #define MOSCOM_LSR_RXBREAK 0x10
124 #define MOSCOM_LSR_TXEMPTY 0x20
125 #define MOSCOM_LSR_TXALLEMPTY 0x40
126 #define MOSCOM_LSR_TXFIFO_ERR 0x80
128 #define MOSCOM_MSR_CTS_CHG 0x01
129 #define MOSCOM_MSR_DSR_CHG 0x02
130 #define MOSCOM_MSR_RI_CHG 0x04
131 #define MOSCOM_MSR_CD_CHG 0x08
132 #define MOSCOM_MSR_CTS 0x10
133 #define MOSCOM_MSR_RTS 0x20
134 #define MOSCOM_MSR_RI 0x40
135 #define MOSCOM_MSR_CD 0x80
137 #define MOSCOM_BAUD_REF 115200
139 struct moscom_softc
{
140 USBBASEDEVICE sc_dev
;
141 usbd_device_handle sc_udev
;
142 usbd_interface_handle sc_iface
;
143 device_ptr_t sc_subdev
;
152 void moscom_get_status(void *, int, u_char
*, u_char
*);
153 void moscom_set(void *, int, int, int);
154 int moscom_param(void *, int, struct termios
*);
155 int moscom_open(void *, int);
156 int moscom_cmd(struct moscom_softc
*, int, int);
158 struct ucom_methods moscom_methods
= {
169 static const struct usb_devno moscom_devs
[] = {
170 { USB_VENDOR_MOSCHIP
, USB_PRODUCT_MOSCHIP_MCS7703
},
171 { USB_VENDOR_MOSCHIP
, USB_PRODUCT_MOSCHIP_MCS7840
}
173 #define moscom_lookup(v, p) usb_lookup(moscom_devs, v, p)
175 int moscom_match(device_t
, cfdata_t
, void *);
176 void moscom_attach(device_t
, device_t
, void *);
177 void moscom_childdet(device_t
, device_t
);
178 int moscom_detach(device_t
, int);
179 int moscom_activate(device_t
, enum devact
);
181 CFATTACH_DECL2_NEW(moscom
, sizeof(struct moscom_softc
), moscom_match
,
182 moscom_attach
, moscom_detach
, moscom_activate
, NULL
, moscom_childdet
);
186 USB_MATCH_START(moscom
, uaa
);
188 return (moscom_lookup(uaa
->vendor
, uaa
->product
) != NULL
?
189 UMATCH_VENDOR_PRODUCT
: UMATCH_NONE
);
194 USB_ATTACH_START(moscom
, sc
, uaa
);
195 usbd_device_handle dev
= uaa
->device
;
196 struct ucom_attach_args uca
;
197 usb_interface_descriptor_t
*id
;
198 usb_endpoint_descriptor_t
*ed
;
206 devinfop
= usbd_devinfo_alloc(dev
, 0);
207 aprint_normal_dev(self
, "%s\n", devinfop
);
208 usbd_devinfo_free(devinfop
);
212 bzero(&uca
, sizeof(uca
));
213 sc
->sc_udev
= uaa
->device
;
215 if (usbd_set_config_index(sc
->sc_udev
, MOSCOM_CONFIG_NO
, 1) != 0) {
216 aprint_error_dev(self
, "could not set configuration no\n");
221 /* get the first interface handle */
222 error
= usbd_device2interface_handle(sc
->sc_udev
, MOSCOM_IFACE_NO
,
225 aprint_error_dev(self
, "could not get interface handle\n");
230 id
= usbd_get_interface_descriptor(sc
->sc_iface
);
232 uca
.bulkin
= uca
.bulkout
= -1;
233 for (i
= 0; i
< id
->bNumEndpoints
; i
++) {
234 ed
= usbd_interface2endpoint_descriptor(sc
->sc_iface
, i
);
236 aprint_error_dev(self
,
237 "no endpoint descriptor found for %d\n", i
);
242 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
243 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
)
244 uca
.bulkin
= ed
->bEndpointAddress
;
245 else if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_OUT
&&
246 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
)
247 uca
.bulkout
= ed
->bEndpointAddress
;
250 if (uca
.bulkin
== -1 || uca
.bulkout
== -1) {
251 aprint_error_dev(self
, "missing endpoint\n");
256 uca
.ibufsize
= MOSCOMBUFSZ
;
257 uca
.obufsize
= MOSCOMBUFSZ
;
258 uca
.ibufsizepad
= MOSCOMBUFSZ
;
260 uca
.device
= sc
->sc_udev
;
261 uca
.iface
= sc
->sc_iface
;
262 uca
.methods
= &moscom_methods
;
266 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH
, sc
->sc_udev
,
269 sc
->sc_subdev
= config_found_sm_loc(self
, "ucombus", NULL
, &uca
,
270 ucomprint
, ucomsubmatch
);
272 USB_ATTACH_SUCCESS_RETURN
;
276 moscom_childdet(device_t self
, device_t child
)
278 struct moscom_softc
*sc
= device_private(self
);
280 KASSERT(sc
->sc_subdev
== child
);
281 sc
->sc_subdev
= NULL
;
286 USB_DETACH_START(moscom
, sc
);
290 if (sc
->sc_subdev
!= NULL
)
291 rv
= config_detach(sc
->sc_subdev
, flags
);
293 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH
, sc
->sc_udev
,
300 moscom_activate(device_t self
, enum devact act
)
302 struct moscom_softc
*sc
= device_private(self
);
305 case DVACT_DEACTIVATE
:
314 moscom_open(void *vsc
, int portno
)
316 struct moscom_softc
*sc
= vsc
;
317 usb_device_request_t req
;
322 /* Purge FIFOs or odd things happen */
323 if (moscom_cmd(sc
, MOSCOM_FIFO
, 0x00) != 0)
326 if (moscom_cmd(sc
, MOSCOM_FIFO
, MOSCOM_FIFO_EN
|
327 MOSCOM_FIFO_RXCLR
| MOSCOM_FIFO_TXCLR
|
328 MOSCOM_FIFO_DMA_BLK
| MOSCOM_FIFO_RXLVL_MASK
) != 0)
331 /* Magic tell device we're ready for data command */
332 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
333 req
.bRequest
= MOSCOM_WRITE
;
334 USETW(req
.wValue
, 0x08);
335 USETW(req
.wIndex
, MOSCOM_INT
);
336 USETW(req
.wLength
, 0);
337 if (usbd_do_request(sc
->sc_udev
, &req
, NULL
) != 0)
344 moscom_set(void *vsc
, int portno
, int reg
, int onoff
)
346 struct moscom_softc
*sc
= vsc
;
351 val
= onoff
? MOSCOM_MCR_DTR
: 0;
354 val
= onoff
? MOSCOM_MCR_RTS
: 0;
359 val
|= MOSCOM_LCR_BREAK
;
360 moscom_cmd(sc
, MOSCOM_LCR
, val
);
366 moscom_cmd(sc
, MOSCOM_MCR
, val
);
370 moscom_param(void *vsc
, int portno
, struct termios
*t
)
372 struct moscom_softc
*sc
= (struct moscom_softc
*)vsc
;
375 if (t
->c_ospeed
<= 0 || t
->c_ospeed
> 115200)
378 data
= MOSCOM_BAUD_REF
/ t
->c_ospeed
;
380 if (data
== 0 || data
> 0xffff)
383 moscom_cmd(sc
, MOSCOM_LCR
, MOSCOM_LCR_DIVLATCH_EN
);
384 moscom_cmd(sc
, MOSCOM_BAUDLO
, data
& 0xFF);
385 moscom_cmd(sc
, MOSCOM_BAUDHI
, (data
>> 8) & 0xFF);
387 if (ISSET(t
->c_cflag
, CSTOPB
))
388 data
= MOSCOM_LCR_STOP_BITS_2
;
390 data
= MOSCOM_LCR_STOP_BITS_1
;
391 if (ISSET(t
->c_cflag
, PARENB
)) {
392 if (ISSET(t
->c_cflag
, PARODD
))
393 data
|= MOSCOM_LCR_PARITY_ODD
;
395 data
|= MOSCOM_LCR_PARITY_EVEN
;
397 data
|= MOSCOM_LCR_PARITY_NONE
;
398 switch (ISSET(t
->c_cflag
, CSIZE
)) {
400 data
|= MOSCOM_LCR_DBITS(5);
403 data
|= MOSCOM_LCR_DBITS(6);
406 data
|= MOSCOM_LCR_DBITS(7);
409 data
|= MOSCOM_LCR_DBITS(8);
414 moscom_cmd(sc
, MOSCOM_LCR
, sc
->sc_lcr
);
417 /* XXX flow control */
418 if (ISSET(t
->c_cflag
, CRTSCTS
))
419 /* rts/cts flow ctl */
420 } else if (ISSET(t
->c_iflag
, IXON
|IXOFF
)) {
421 /* xon/xoff flow ctl */
423 /* disable flow ctl */
431 moscom_get_status(void *vsc
, int portno
, u_char
*lsr
, u_char
*msr
)
433 struct moscom_softc
*sc
= vsc
;
442 moscom_cmd(struct moscom_softc
*sc
, int reg
, int val
)
444 usb_device_request_t req
;
447 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
448 req
.bRequest
= MOSCOM_WRITE
;
449 USETW(req
.wValue
, val
+ MOSCOM_UART_REG
);
450 USETW(req
.wIndex
, reg
);
451 USETW(req
.wLength
, 0);
452 err
= usbd_do_request(sc
->sc_udev
, &req
, NULL
);