112bd3c8bSSascha Wildner /* $OpenBSD: uark.c,v 1.1 2006/08/14 08:30:22 jsg Exp $ */
212bd3c8bSSascha Wildner
312bd3c8bSSascha Wildner /*
412bd3c8bSSascha Wildner * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
512bd3c8bSSascha Wildner *
612bd3c8bSSascha Wildner * Permission to use, copy, modify, and distribute this software for any
712bd3c8bSSascha Wildner * purpose with or without fee is hereby granted, provided that the above
812bd3c8bSSascha Wildner * copyright notice and this permission notice appear in all copies.
912bd3c8bSSascha Wildner *
1012bd3c8bSSascha Wildner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1112bd3c8bSSascha Wildner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1212bd3c8bSSascha Wildner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1312bd3c8bSSascha Wildner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1412bd3c8bSSascha Wildner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1512bd3c8bSSascha Wildner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1612bd3c8bSSascha Wildner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1712bd3c8bSSascha Wildner *
1812bd3c8bSSascha Wildner * $FreeBSD$
1912bd3c8bSSascha Wildner */
2012bd3c8bSSascha Wildner
2112bd3c8bSSascha Wildner /*
2212bd3c8bSSascha Wildner * NOTE: all function names beginning like "uark_cfg_" can only
2312bd3c8bSSascha Wildner * be called from within the config thread function !
2412bd3c8bSSascha Wildner */
2512bd3c8bSSascha Wildner
2612bd3c8bSSascha Wildner
2712bd3c8bSSascha Wildner #include <sys/stdint.h>
2812bd3c8bSSascha Wildner #include <sys/param.h>
2912bd3c8bSSascha Wildner #include <sys/queue.h>
3012bd3c8bSSascha Wildner #include <sys/types.h>
3112bd3c8bSSascha Wildner #include <sys/systm.h>
3212bd3c8bSSascha Wildner #include <sys/kernel.h>
3312bd3c8bSSascha Wildner #include <sys/bus.h>
3412bd3c8bSSascha Wildner #include <sys/module.h>
3512bd3c8bSSascha Wildner #include <sys/lock.h>
3612bd3c8bSSascha Wildner #include <sys/condvar.h>
3712bd3c8bSSascha Wildner #include <sys/sysctl.h>
3812bd3c8bSSascha Wildner #include <sys/unistd.h>
3912bd3c8bSSascha Wildner #include <sys/callout.h>
4012bd3c8bSSascha Wildner #include <sys/malloc.h>
41*2b3f93eaSMatthew Dillon #include <sys/caps.h>
4212bd3c8bSSascha Wildner
43a81829f2SSascha Wildner #include <bus/u4b/usb.h>
44a81829f2SSascha Wildner #include <bus/u4b/usbdi.h>
45a81829f2SSascha Wildner #include <bus/u4b/usbdi_util.h>
46a81829f2SSascha Wildner #include <bus/u4b/usbhid.h>
4759f64dacSMarkus Pfeiffer
4859f64dacSMarkus Pfeiffer #include "usbdevs.h"
4912bd3c8bSSascha Wildner
5012bd3c8bSSascha Wildner #define USB_DEBUG_VAR usb_debug
51a81829f2SSascha Wildner #include <bus/u4b/usb_debug.h>
52a81829f2SSascha Wildner #include <bus/u4b/usb_process.h>
5312bd3c8bSSascha Wildner
54a81829f2SSascha Wildner #include <bus/u4b/serial/usb_serial.h>
5512bd3c8bSSascha Wildner
5612bd3c8bSSascha Wildner #define UARK_BUF_SIZE 1024 /* bytes */
5712bd3c8bSSascha Wildner
5812bd3c8bSSascha Wildner #define UARK_SET_DATA_BITS(x) ((x) - 5)
5912bd3c8bSSascha Wildner
6012bd3c8bSSascha Wildner #define UARK_PARITY_NONE 0x00
6112bd3c8bSSascha Wildner #define UARK_PARITY_ODD 0x08
6212bd3c8bSSascha Wildner #define UARK_PARITY_EVEN 0x18
6312bd3c8bSSascha Wildner
6412bd3c8bSSascha Wildner #define UARK_STOP_BITS_1 0x00
6512bd3c8bSSascha Wildner #define UARK_STOP_BITS_2 0x04
6612bd3c8bSSascha Wildner
6712bd3c8bSSascha Wildner #define UARK_BAUD_REF 3000000
6812bd3c8bSSascha Wildner
6912bd3c8bSSascha Wildner #define UARK_WRITE 0x40
7012bd3c8bSSascha Wildner #define UARK_READ 0xc0
7112bd3c8bSSascha Wildner
7212bd3c8bSSascha Wildner #define UARK_REQUEST 0xfe
7312bd3c8bSSascha Wildner
7412bd3c8bSSascha Wildner #define UARK_CONFIG_INDEX 0
7512bd3c8bSSascha Wildner #define UARK_IFACE_INDEX 0
7612bd3c8bSSascha Wildner
7712bd3c8bSSascha Wildner enum {
7812bd3c8bSSascha Wildner UARK_BULK_DT_WR,
7912bd3c8bSSascha Wildner UARK_BULK_DT_RD,
8012bd3c8bSSascha Wildner UARK_N_TRANSFER,
8112bd3c8bSSascha Wildner };
8212bd3c8bSSascha Wildner
8312bd3c8bSSascha Wildner struct uark_softc {
8412bd3c8bSSascha Wildner struct ucom_super_softc sc_super_ucom;
8512bd3c8bSSascha Wildner struct ucom_softc sc_ucom;
8612bd3c8bSSascha Wildner
8712bd3c8bSSascha Wildner struct usb_xfer *sc_xfer[UARK_N_TRANSFER];
8812bd3c8bSSascha Wildner struct usb_device *sc_udev;
89a81829f2SSascha Wildner struct lock sc_lock;
9012bd3c8bSSascha Wildner
9112bd3c8bSSascha Wildner uint8_t sc_msr;
9212bd3c8bSSascha Wildner uint8_t sc_lsr;
9312bd3c8bSSascha Wildner };
9412bd3c8bSSascha Wildner
9512bd3c8bSSascha Wildner /* prototypes */
9612bd3c8bSSascha Wildner
9712bd3c8bSSascha Wildner static device_probe_t uark_probe;
9812bd3c8bSSascha Wildner static device_attach_t uark_attach;
9912bd3c8bSSascha Wildner static device_detach_t uark_detach;
10012bd3c8bSSascha Wildner
10112bd3c8bSSascha Wildner static usb_callback_t uark_bulk_write_callback;
10212bd3c8bSSascha Wildner static usb_callback_t uark_bulk_read_callback;
10312bd3c8bSSascha Wildner
10412bd3c8bSSascha Wildner static void uark_start_read(struct ucom_softc *);
10512bd3c8bSSascha Wildner static void uark_stop_read(struct ucom_softc *);
10612bd3c8bSSascha Wildner static void uark_start_write(struct ucom_softc *);
10712bd3c8bSSascha Wildner static void uark_stop_write(struct ucom_softc *);
10812bd3c8bSSascha Wildner static int uark_pre_param(struct ucom_softc *, struct termios *);
10912bd3c8bSSascha Wildner static void uark_cfg_param(struct ucom_softc *, struct termios *);
11012bd3c8bSSascha Wildner static void uark_cfg_get_status(struct ucom_softc *, uint8_t *,
11112bd3c8bSSascha Wildner uint8_t *);
11212bd3c8bSSascha Wildner static void uark_cfg_set_break(struct ucom_softc *, uint8_t);
11312bd3c8bSSascha Wildner static void uark_cfg_write(struct uark_softc *, uint16_t, uint16_t);
11412bd3c8bSSascha Wildner static void uark_poll(struct ucom_softc *ucom);
11512bd3c8bSSascha Wildner
11612bd3c8bSSascha Wildner static const struct usb_config
11712bd3c8bSSascha Wildner uark_xfer_config[UARK_N_TRANSFER] = {
11812bd3c8bSSascha Wildner
11912bd3c8bSSascha Wildner [UARK_BULK_DT_WR] = {
12012bd3c8bSSascha Wildner .type = UE_BULK,
12112bd3c8bSSascha Wildner .endpoint = UE_ADDR_ANY,
12212bd3c8bSSascha Wildner .direction = UE_DIR_OUT,
12312bd3c8bSSascha Wildner .bufsize = UARK_BUF_SIZE,
12412bd3c8bSSascha Wildner .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
12512bd3c8bSSascha Wildner .callback = &uark_bulk_write_callback,
12612bd3c8bSSascha Wildner },
12712bd3c8bSSascha Wildner
12812bd3c8bSSascha Wildner [UARK_BULK_DT_RD] = {
12912bd3c8bSSascha Wildner .type = UE_BULK,
13012bd3c8bSSascha Wildner .endpoint = UE_ADDR_ANY,
13112bd3c8bSSascha Wildner .direction = UE_DIR_IN,
13212bd3c8bSSascha Wildner .bufsize = UARK_BUF_SIZE,
13312bd3c8bSSascha Wildner .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
13412bd3c8bSSascha Wildner .callback = &uark_bulk_read_callback,
13512bd3c8bSSascha Wildner },
13612bd3c8bSSascha Wildner };
13712bd3c8bSSascha Wildner
13812bd3c8bSSascha Wildner static const struct ucom_callback uark_callback = {
13912bd3c8bSSascha Wildner .ucom_cfg_get_status = &uark_cfg_get_status,
14012bd3c8bSSascha Wildner .ucom_cfg_set_break = &uark_cfg_set_break,
14112bd3c8bSSascha Wildner .ucom_cfg_param = &uark_cfg_param,
14212bd3c8bSSascha Wildner .ucom_pre_param = &uark_pre_param,
14312bd3c8bSSascha Wildner .ucom_start_read = &uark_start_read,
14412bd3c8bSSascha Wildner .ucom_stop_read = &uark_stop_read,
14512bd3c8bSSascha Wildner .ucom_start_write = &uark_start_write,
14612bd3c8bSSascha Wildner .ucom_stop_write = &uark_stop_write,
14712bd3c8bSSascha Wildner .ucom_poll = &uark_poll,
14812bd3c8bSSascha Wildner };
14912bd3c8bSSascha Wildner
15012bd3c8bSSascha Wildner static device_method_t uark_methods[] = {
15112bd3c8bSSascha Wildner /* Device methods */
15212bd3c8bSSascha Wildner DEVMETHOD(device_probe, uark_probe),
15312bd3c8bSSascha Wildner DEVMETHOD(device_attach, uark_attach),
15412bd3c8bSSascha Wildner DEVMETHOD(device_detach, uark_detach),
155d3c9c58eSSascha Wildner DEVMETHOD_END
15612bd3c8bSSascha Wildner };
15712bd3c8bSSascha Wildner
15812bd3c8bSSascha Wildner static devclass_t uark_devclass;
15912bd3c8bSSascha Wildner
16012bd3c8bSSascha Wildner static driver_t uark_driver = {
16112bd3c8bSSascha Wildner .name = "uark",
16212bd3c8bSSascha Wildner .methods = uark_methods,
16312bd3c8bSSascha Wildner .size = sizeof(struct uark_softc),
16412bd3c8bSSascha Wildner };
16512bd3c8bSSascha Wildner
1663a25be87SSascha Wildner DRIVER_MODULE(uark, uhub, uark_driver, uark_devclass, NULL, NULL);
16712bd3c8bSSascha Wildner MODULE_DEPEND(uark, ucom, 1, 1, 1);
16812bd3c8bSSascha Wildner MODULE_DEPEND(uark, usb, 1, 1, 1);
16912bd3c8bSSascha Wildner MODULE_VERSION(uark, 1);
17012bd3c8bSSascha Wildner
17112bd3c8bSSascha Wildner static const STRUCT_USB_HOST_ID uark_devs[] = {
17212bd3c8bSSascha Wildner {USB_VPI(USB_VENDOR_ARKMICRO, USB_PRODUCT_ARKMICRO_ARK3116, 0)},
17312bd3c8bSSascha Wildner };
17412bd3c8bSSascha Wildner
17512bd3c8bSSascha Wildner static int
uark_probe(device_t dev)17612bd3c8bSSascha Wildner uark_probe(device_t dev)
17712bd3c8bSSascha Wildner {
17812bd3c8bSSascha Wildner struct usb_attach_arg *uaa = device_get_ivars(dev);
17912bd3c8bSSascha Wildner
18012bd3c8bSSascha Wildner if (uaa->usb_mode != USB_MODE_HOST) {
18112bd3c8bSSascha Wildner return (ENXIO);
18212bd3c8bSSascha Wildner }
18312bd3c8bSSascha Wildner if (uaa->info.bConfigIndex != 0) {
18412bd3c8bSSascha Wildner return (ENXIO);
18512bd3c8bSSascha Wildner }
18612bd3c8bSSascha Wildner if (uaa->info.bIfaceIndex != UARK_IFACE_INDEX) {
18712bd3c8bSSascha Wildner return (ENXIO);
18812bd3c8bSSascha Wildner }
18912bd3c8bSSascha Wildner return (usbd_lookup_id_by_uaa(uark_devs, sizeof(uark_devs), uaa));
19012bd3c8bSSascha Wildner }
19112bd3c8bSSascha Wildner
19212bd3c8bSSascha Wildner static int
uark_attach(device_t dev)19312bd3c8bSSascha Wildner uark_attach(device_t dev)
19412bd3c8bSSascha Wildner {
19512bd3c8bSSascha Wildner struct usb_attach_arg *uaa = device_get_ivars(dev);
19612bd3c8bSSascha Wildner struct uark_softc *sc = device_get_softc(dev);
19712bd3c8bSSascha Wildner int32_t error;
19812bd3c8bSSascha Wildner uint8_t iface_index;
19912bd3c8bSSascha Wildner
20012bd3c8bSSascha Wildner device_set_usb_desc(dev);
201a81829f2SSascha Wildner lockinit(&sc->sc_lock, "uark", 0, LK_CANRECURSE);
20212bd3c8bSSascha Wildner
20312bd3c8bSSascha Wildner sc->sc_udev = uaa->device;
20412bd3c8bSSascha Wildner
20512bd3c8bSSascha Wildner iface_index = UARK_IFACE_INDEX;
20612bd3c8bSSascha Wildner error = usbd_transfer_setup
20712bd3c8bSSascha Wildner (uaa->device, &iface_index, sc->sc_xfer,
208a81829f2SSascha Wildner uark_xfer_config, UARK_N_TRANSFER, sc, &sc->sc_lock);
20912bd3c8bSSascha Wildner
21012bd3c8bSSascha Wildner if (error) {
21112bd3c8bSSascha Wildner device_printf(dev, "allocating control USB "
21212bd3c8bSSascha Wildner "transfers failed\n");
21312bd3c8bSSascha Wildner goto detach;
21412bd3c8bSSascha Wildner }
21512bd3c8bSSascha Wildner /* clear stall at first run */
216a81829f2SSascha Wildner lockmgr(&sc->sc_lock, LK_EXCLUSIVE);
21712bd3c8bSSascha Wildner usbd_xfer_set_stall(sc->sc_xfer[UARK_BULK_DT_WR]);
21812bd3c8bSSascha Wildner usbd_xfer_set_stall(sc->sc_xfer[UARK_BULK_DT_RD]);
219a81829f2SSascha Wildner lockmgr(&sc->sc_lock, LK_RELEASE);
22012bd3c8bSSascha Wildner
22112bd3c8bSSascha Wildner error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
222a81829f2SSascha Wildner &uark_callback, &sc->sc_lock);
22312bd3c8bSSascha Wildner if (error) {
22412bd3c8bSSascha Wildner DPRINTF("ucom_attach failed\n");
22512bd3c8bSSascha Wildner goto detach;
22612bd3c8bSSascha Wildner }
22712bd3c8bSSascha Wildner ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
22812bd3c8bSSascha Wildner
22912bd3c8bSSascha Wildner return (0); /* success */
23012bd3c8bSSascha Wildner
23112bd3c8bSSascha Wildner detach:
23212bd3c8bSSascha Wildner uark_detach(dev);
23312bd3c8bSSascha Wildner return (ENXIO); /* failure */
23412bd3c8bSSascha Wildner }
23512bd3c8bSSascha Wildner
23612bd3c8bSSascha Wildner static int
uark_detach(device_t dev)23712bd3c8bSSascha Wildner uark_detach(device_t dev)
23812bd3c8bSSascha Wildner {
23912bd3c8bSSascha Wildner struct uark_softc *sc = device_get_softc(dev);
24012bd3c8bSSascha Wildner
24112bd3c8bSSascha Wildner ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
24212bd3c8bSSascha Wildner usbd_transfer_unsetup(sc->sc_xfer, UARK_N_TRANSFER);
243a81829f2SSascha Wildner lockuninit(&sc->sc_lock);
24412bd3c8bSSascha Wildner
24512bd3c8bSSascha Wildner return (0);
24612bd3c8bSSascha Wildner }
24712bd3c8bSSascha Wildner
24812bd3c8bSSascha Wildner static void
uark_bulk_write_callback(struct usb_xfer * xfer,usb_error_t error)24912bd3c8bSSascha Wildner uark_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
25012bd3c8bSSascha Wildner {
25112bd3c8bSSascha Wildner struct uark_softc *sc = usbd_xfer_softc(xfer);
25212bd3c8bSSascha Wildner struct usb_page_cache *pc;
25312bd3c8bSSascha Wildner uint32_t actlen;
25412bd3c8bSSascha Wildner
25512bd3c8bSSascha Wildner switch (USB_GET_STATE(xfer)) {
25612bd3c8bSSascha Wildner case USB_ST_SETUP:
25712bd3c8bSSascha Wildner case USB_ST_TRANSFERRED:
25812bd3c8bSSascha Wildner tr_setup:
25912bd3c8bSSascha Wildner pc = usbd_xfer_get_frame(xfer, 0);
26012bd3c8bSSascha Wildner if (ucom_get_data(&sc->sc_ucom, pc, 0,
26112bd3c8bSSascha Wildner UARK_BUF_SIZE, &actlen)) {
26212bd3c8bSSascha Wildner usbd_xfer_set_frame_len(xfer, 0, actlen);
26312bd3c8bSSascha Wildner usbd_transfer_submit(xfer);
26412bd3c8bSSascha Wildner }
26512bd3c8bSSascha Wildner return;
26612bd3c8bSSascha Wildner
26712bd3c8bSSascha Wildner default: /* Error */
26812bd3c8bSSascha Wildner if (error != USB_ERR_CANCELLED) {
26912bd3c8bSSascha Wildner /* try to clear stall first */
27012bd3c8bSSascha Wildner usbd_xfer_set_stall(xfer);
27112bd3c8bSSascha Wildner goto tr_setup;
27212bd3c8bSSascha Wildner }
27312bd3c8bSSascha Wildner return;
27412bd3c8bSSascha Wildner
27512bd3c8bSSascha Wildner }
27612bd3c8bSSascha Wildner }
27712bd3c8bSSascha Wildner
27812bd3c8bSSascha Wildner static void
uark_bulk_read_callback(struct usb_xfer * xfer,usb_error_t error)27912bd3c8bSSascha Wildner uark_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
28012bd3c8bSSascha Wildner {
28112bd3c8bSSascha Wildner struct uark_softc *sc = usbd_xfer_softc(xfer);
28212bd3c8bSSascha Wildner struct usb_page_cache *pc;
28312bd3c8bSSascha Wildner int actlen;
28412bd3c8bSSascha Wildner
28512bd3c8bSSascha Wildner usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
28612bd3c8bSSascha Wildner
28712bd3c8bSSascha Wildner switch (USB_GET_STATE(xfer)) {
28812bd3c8bSSascha Wildner case USB_ST_TRANSFERRED:
28912bd3c8bSSascha Wildner pc = usbd_xfer_get_frame(xfer, 0);
29012bd3c8bSSascha Wildner ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
29112bd3c8bSSascha Wildner
29212bd3c8bSSascha Wildner case USB_ST_SETUP:
29312bd3c8bSSascha Wildner tr_setup:
29412bd3c8bSSascha Wildner usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
29512bd3c8bSSascha Wildner usbd_transfer_submit(xfer);
29612bd3c8bSSascha Wildner return;
29712bd3c8bSSascha Wildner
29812bd3c8bSSascha Wildner default: /* Error */
29912bd3c8bSSascha Wildner if (error != USB_ERR_CANCELLED) {
30012bd3c8bSSascha Wildner /* try to clear stall first */
30112bd3c8bSSascha Wildner usbd_xfer_set_stall(xfer);
30212bd3c8bSSascha Wildner goto tr_setup;
30312bd3c8bSSascha Wildner }
30412bd3c8bSSascha Wildner return;
30512bd3c8bSSascha Wildner }
30612bd3c8bSSascha Wildner }
30712bd3c8bSSascha Wildner
30812bd3c8bSSascha Wildner static void
uark_start_read(struct ucom_softc * ucom)30912bd3c8bSSascha Wildner uark_start_read(struct ucom_softc *ucom)
31012bd3c8bSSascha Wildner {
31112bd3c8bSSascha Wildner struct uark_softc *sc = ucom->sc_parent;
31212bd3c8bSSascha Wildner
31312bd3c8bSSascha Wildner usbd_transfer_start(sc->sc_xfer[UARK_BULK_DT_RD]);
31412bd3c8bSSascha Wildner }
31512bd3c8bSSascha Wildner
31612bd3c8bSSascha Wildner static void
uark_stop_read(struct ucom_softc * ucom)31712bd3c8bSSascha Wildner uark_stop_read(struct ucom_softc *ucom)
31812bd3c8bSSascha Wildner {
31912bd3c8bSSascha Wildner struct uark_softc *sc = ucom->sc_parent;
32012bd3c8bSSascha Wildner
32112bd3c8bSSascha Wildner usbd_transfer_stop(sc->sc_xfer[UARK_BULK_DT_RD]);
32212bd3c8bSSascha Wildner }
32312bd3c8bSSascha Wildner
32412bd3c8bSSascha Wildner static void
uark_start_write(struct ucom_softc * ucom)32512bd3c8bSSascha Wildner uark_start_write(struct ucom_softc *ucom)
32612bd3c8bSSascha Wildner {
32712bd3c8bSSascha Wildner struct uark_softc *sc = ucom->sc_parent;
32812bd3c8bSSascha Wildner
32912bd3c8bSSascha Wildner usbd_transfer_start(sc->sc_xfer[UARK_BULK_DT_WR]);
33012bd3c8bSSascha Wildner }
33112bd3c8bSSascha Wildner
33212bd3c8bSSascha Wildner static void
uark_stop_write(struct ucom_softc * ucom)33312bd3c8bSSascha Wildner uark_stop_write(struct ucom_softc *ucom)
33412bd3c8bSSascha Wildner {
33512bd3c8bSSascha Wildner struct uark_softc *sc = ucom->sc_parent;
33612bd3c8bSSascha Wildner
33712bd3c8bSSascha Wildner usbd_transfer_stop(sc->sc_xfer[UARK_BULK_DT_WR]);
33812bd3c8bSSascha Wildner }
33912bd3c8bSSascha Wildner
34012bd3c8bSSascha Wildner static int
uark_pre_param(struct ucom_softc * ucom,struct termios * t)34112bd3c8bSSascha Wildner uark_pre_param(struct ucom_softc *ucom, struct termios *t)
34212bd3c8bSSascha Wildner {
34312bd3c8bSSascha Wildner if ((t->c_ospeed < 300) || (t->c_ospeed > 115200))
34412bd3c8bSSascha Wildner return (EINVAL);
34512bd3c8bSSascha Wildner return (0);
34612bd3c8bSSascha Wildner }
34712bd3c8bSSascha Wildner
34812bd3c8bSSascha Wildner static void
uark_cfg_param(struct ucom_softc * ucom,struct termios * t)34912bd3c8bSSascha Wildner uark_cfg_param(struct ucom_softc *ucom, struct termios *t)
35012bd3c8bSSascha Wildner {
35112bd3c8bSSascha Wildner struct uark_softc *sc = ucom->sc_parent;
35212bd3c8bSSascha Wildner uint32_t speed = t->c_ospeed;
35312bd3c8bSSascha Wildner uint16_t data;
35412bd3c8bSSascha Wildner
35512bd3c8bSSascha Wildner /*
35612bd3c8bSSascha Wildner * NOTE: When reverse computing the baud rate from the "data" all
35712bd3c8bSSascha Wildner * allowed baud rates are within 3% of the initial baud rate.
35812bd3c8bSSascha Wildner */
35912bd3c8bSSascha Wildner data = (UARK_BAUD_REF + (speed / 2)) / speed;
36012bd3c8bSSascha Wildner
36112bd3c8bSSascha Wildner uark_cfg_write(sc, 3, 0x83);
36212bd3c8bSSascha Wildner uark_cfg_write(sc, 0, data & 0xFF);
36312bd3c8bSSascha Wildner uark_cfg_write(sc, 1, data >> 8);
36412bd3c8bSSascha Wildner uark_cfg_write(sc, 3, 0x03);
36512bd3c8bSSascha Wildner
36612bd3c8bSSascha Wildner if (t->c_cflag & CSTOPB)
36712bd3c8bSSascha Wildner data = UARK_STOP_BITS_2;
36812bd3c8bSSascha Wildner else
36912bd3c8bSSascha Wildner data = UARK_STOP_BITS_1;
37012bd3c8bSSascha Wildner
37112bd3c8bSSascha Wildner if (t->c_cflag & PARENB) {
37212bd3c8bSSascha Wildner if (t->c_cflag & PARODD)
37312bd3c8bSSascha Wildner data |= UARK_PARITY_ODD;
37412bd3c8bSSascha Wildner else
37512bd3c8bSSascha Wildner data |= UARK_PARITY_EVEN;
37612bd3c8bSSascha Wildner } else
37712bd3c8bSSascha Wildner data |= UARK_PARITY_NONE;
37812bd3c8bSSascha Wildner
37912bd3c8bSSascha Wildner switch (t->c_cflag & CSIZE) {
38012bd3c8bSSascha Wildner case CS5:
38112bd3c8bSSascha Wildner data |= UARK_SET_DATA_BITS(5);
38212bd3c8bSSascha Wildner break;
38312bd3c8bSSascha Wildner case CS6:
38412bd3c8bSSascha Wildner data |= UARK_SET_DATA_BITS(6);
38512bd3c8bSSascha Wildner break;
38612bd3c8bSSascha Wildner case CS7:
38712bd3c8bSSascha Wildner data |= UARK_SET_DATA_BITS(7);
38812bd3c8bSSascha Wildner break;
38912bd3c8bSSascha Wildner default:
39012bd3c8bSSascha Wildner case CS8:
39112bd3c8bSSascha Wildner data |= UARK_SET_DATA_BITS(8);
39212bd3c8bSSascha Wildner break;
39312bd3c8bSSascha Wildner }
39412bd3c8bSSascha Wildner uark_cfg_write(sc, 3, 0x00);
39512bd3c8bSSascha Wildner uark_cfg_write(sc, 3, data);
39612bd3c8bSSascha Wildner }
39712bd3c8bSSascha Wildner
39812bd3c8bSSascha Wildner static void
uark_cfg_get_status(struct ucom_softc * ucom,uint8_t * lsr,uint8_t * msr)39912bd3c8bSSascha Wildner uark_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
40012bd3c8bSSascha Wildner {
40112bd3c8bSSascha Wildner struct uark_softc *sc = ucom->sc_parent;
40212bd3c8bSSascha Wildner
40312bd3c8bSSascha Wildner *lsr = sc->sc_lsr;
40412bd3c8bSSascha Wildner *msr = sc->sc_msr;
40512bd3c8bSSascha Wildner }
40612bd3c8bSSascha Wildner
40712bd3c8bSSascha Wildner static void
uark_cfg_set_break(struct ucom_softc * ucom,uint8_t onoff)40812bd3c8bSSascha Wildner uark_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
40912bd3c8bSSascha Wildner {
41012bd3c8bSSascha Wildner struct uark_softc *sc = ucom->sc_parent;
41112bd3c8bSSascha Wildner
41212bd3c8bSSascha Wildner DPRINTF("onoff=%d\n", onoff);
41312bd3c8bSSascha Wildner
41412bd3c8bSSascha Wildner uark_cfg_write(sc, 4, onoff ? 0x01 : 0x00);
41512bd3c8bSSascha Wildner }
41612bd3c8bSSascha Wildner
41712bd3c8bSSascha Wildner static void
uark_cfg_write(struct uark_softc * sc,uint16_t index,uint16_t value)41812bd3c8bSSascha Wildner uark_cfg_write(struct uark_softc *sc, uint16_t index, uint16_t value)
41912bd3c8bSSascha Wildner {
42012bd3c8bSSascha Wildner struct usb_device_request req;
42112bd3c8bSSascha Wildner usb_error_t err;
42212bd3c8bSSascha Wildner
42312bd3c8bSSascha Wildner req.bmRequestType = UARK_WRITE;
42412bd3c8bSSascha Wildner req.bRequest = UARK_REQUEST;
42512bd3c8bSSascha Wildner USETW(req.wValue, value);
42612bd3c8bSSascha Wildner USETW(req.wIndex, index);
42712bd3c8bSSascha Wildner USETW(req.wLength, 0);
42812bd3c8bSSascha Wildner
42912bd3c8bSSascha Wildner err = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
43012bd3c8bSSascha Wildner &req, NULL, 0, 1000);
43112bd3c8bSSascha Wildner if (err) {
43212bd3c8bSSascha Wildner DPRINTFN(0, "device request failed, err=%s "
43312bd3c8bSSascha Wildner "(ignored)\n", usbd_errstr(err));
43412bd3c8bSSascha Wildner }
43512bd3c8bSSascha Wildner }
43612bd3c8bSSascha Wildner
43712bd3c8bSSascha Wildner static void
uark_poll(struct ucom_softc * ucom)43812bd3c8bSSascha Wildner uark_poll(struct ucom_softc *ucom)
43912bd3c8bSSascha Wildner {
44012bd3c8bSSascha Wildner struct uark_softc *sc = ucom->sc_parent;
44112bd3c8bSSascha Wildner usbd_transfer_poll(sc->sc_xfer, UARK_N_TRANSFER);
44212bd3c8bSSascha Wildner }
443