| File: | dev/usb/ukspan.c |
| Warning: | line 479, column 2 Value stored to 'div' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: ukspan.c,v 1.4 2022/04/09 20:07:44 naddy Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 2019 Cody Cutler <ccutler@csail.mit.edu> |
| 5 | * |
| 6 | * Permission to use, copy, modify, and distribute this software for any |
| 7 | * purpose with or without fee is hereby granted, provided that the above |
| 8 | * copyright notice and this permission notice appear in all copies. |
| 9 | * |
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 17 | */ |
| 18 | |
| 19 | /* |
| 20 | * I don't know of any technical documentation for the Keyspan USA-19HS. I |
| 21 | * inspected the Linux driver (drivers/usb/serial/keyspan_usa90msg.h) to learn |
| 22 | * the device message format and the procedure for setting the baud rate. |
| 23 | */ |
| 24 | |
| 25 | #include <sys/param.h> |
| 26 | #include <sys/systm.h> |
| 27 | #include <sys/tty.h> |
| 28 | |
| 29 | #include <dev/usb/usb.h> |
| 30 | #include <dev/usb/usbdevs.h> |
| 31 | #include <dev/usb/usbdi.h> |
| 32 | #include <dev/usb/usbdi_util.h> |
| 33 | |
| 34 | #include <dev/usb/ucomvar.h> |
| 35 | |
| 36 | /*#define UKSPAN_DEBUG */ |
| 37 | |
| 38 | #ifdef UKSPAN_DEBUG |
| 39 | #define DPRINTF(x...)do { ; } while (0) do { printf(x); } while (0) |
| 40 | #else |
| 41 | #define DPRINTF(x...)do { ; } while (0) do { ; } while (0) |
| 42 | #endif |
| 43 | |
| 44 | #define UKSPAN_PARITY_NONE0x0 0x0 |
| 45 | #define UKSPAN_PARITY_ODD0x08 0x08 |
| 46 | #define UKSPAN_PARITY_EVEN0x18 0x18 |
| 47 | |
| 48 | #define UKSPAN_DATA_50x0 0x0 |
| 49 | #define UKSPAN_DATA_60x1 0x1 |
| 50 | #define UKSPAN_DATA_70x2 0x2 |
| 51 | #define UKSPAN_DATA_80x3 0x3 |
| 52 | |
| 53 | #define UKSPAN_STOP_10x0 0x0 |
| 54 | #define UKSPAN_STOP_20x4 0x4 |
| 55 | |
| 56 | #define UKSPAN_MAGIC0x2 0x2 |
| 57 | |
| 58 | #define UKSPAN_CLOCK14769231 14769231 |
| 59 | |
| 60 | /* |
| 61 | * The following USB indexes and endpoint addresses may be specific to the |
| 62 | * Keyspan USA19HS device |
| 63 | */ |
| 64 | #define UKSPAN_CONFIG_IDX1 1 |
| 65 | #define UKSPAN_IFACE_IDX0 0 |
| 66 | |
| 67 | #define UKSPAN_EA_BULKIN(0x80 | 1) (UE_DIR_IN0x80 | 1) |
| 68 | #define UKSPAN_EA_BULKOUT(0x00 | 1) (UE_DIR_OUT0x00 | 1) |
| 69 | #define UKSPAN_EA_CONFIGIN(0x80 | 2) (UE_DIR_IN0x80 | 2) |
| 70 | #define UKSPAN_EA_CONFIGOUT(0x00 | 2) (UE_DIR_OUT0x00 | 2) |
| 71 | |
| 72 | /* Sent to device on control out endpoint */ |
| 73 | struct ukspan_cmsg { |
| 74 | uint8_t setclock; |
| 75 | uint8_t baudlo; |
| 76 | uint8_t baudhi; |
| 77 | uint8_t setlcr; |
| 78 | uint8_t lcr; |
| 79 | uint8_t setrxmode; |
| 80 | uint8_t rxmode; |
| 81 | uint8_t settxmode; |
| 82 | uint8_t txmode; |
| 83 | uint8_t settxflowcontrol; |
| 84 | uint8_t txflowcontrol; |
| 85 | uint8_t setrxflowcontrol; |
| 86 | uint8_t rxflowcontrol; |
| 87 | uint8_t sendxoff; |
| 88 | uint8_t sendxon; |
| 89 | uint8_t xonchar; |
| 90 | uint8_t xoffchar; |
| 91 | uint8_t sendchar; |
| 92 | uint8_t txchar; |
| 93 | uint8_t setrts; |
| 94 | uint8_t rts; |
| 95 | uint8_t setdtr; |
| 96 | uint8_t dtr; |
| 97 | |
| 98 | uint8_t rxforwardingchars; |
| 99 | uint8_t rxforwardingtimeoutms; |
| 100 | uint8_t txacksetting; |
| 101 | |
| 102 | uint8_t portenabled; |
| 103 | uint8_t txflush; |
| 104 | uint8_t txbreak; |
| 105 | uint8_t loopbackmode; |
| 106 | |
| 107 | uint8_t rxflush; |
| 108 | uint8_t rxforward; |
| 109 | uint8_t cancelrxoff; |
| 110 | uint8_t returnstatus; |
| 111 | } __packed__attribute__((__packed__)); |
| 112 | |
| 113 | /* Received from device on control in endpoint */ |
| 114 | struct ukspan_smsg { |
| 115 | uint8_t msr; |
| 116 | uint8_t cts; |
| 117 | uint8_t dcd; |
| 118 | uint8_t dsr; |
| 119 | uint8_t ri; |
| 120 | uint8_t txxoff; |
| 121 | uint8_t rxbreak; |
| 122 | uint8_t rxoverrun; |
| 123 | uint8_t rxparity; |
| 124 | uint8_t rxframe; |
| 125 | uint8_t portstate; |
| 126 | uint8_t messageack; |
| 127 | uint8_t charack; |
| 128 | uint8_t controlresp; |
| 129 | } __packed__attribute__((__packed__)); |
| 130 | |
| 131 | struct ukspan_softc { |
| 132 | struct device sc_dev; |
| 133 | struct usbd_device *udev; |
| 134 | struct usbd_interface *iface; |
| 135 | struct usbd_pipe *cout_pipe; |
| 136 | struct usbd_pipe *cin_pipe; |
| 137 | struct usbd_xfer *ixfer; |
| 138 | struct usbd_xfer *oxfer; |
| 139 | struct device *ucom_dev; |
| 140 | struct ukspan_smsg smsg; |
| 141 | struct ukspan_cmsg cmsg; |
| 142 | u_char lsr; |
| 143 | u_char msr; |
| 144 | }; |
| 145 | |
| 146 | int ukspan_match(struct device *, void *, void *); |
| 147 | void ukspan_attach(struct device *, struct device *, void *); |
| 148 | int ukspan_detach(struct device *, int); |
| 149 | |
| 150 | void ukspan_close(void *, int); |
| 151 | int ukspan_open(void *, int); |
| 152 | int ukspan_param(void *, int, struct termios *); |
| 153 | void ukspan_set(void *, int, int, int); |
| 154 | void ukspan_get_status(void *, int, u_char *, u_char *); |
| 155 | |
| 156 | void ukspan_cmsg_init(bool_Bool, struct ukspan_cmsg *); |
| 157 | int ukspan_cmsg_send(struct ukspan_softc *); |
| 158 | void ukspan_incb(struct usbd_xfer *, void *, usbd_status); |
| 159 | void ukspan_outcb(struct usbd_xfer *, void *, usbd_status); |
| 160 | void ukspan_destroy(struct ukspan_softc *); |
| 161 | |
| 162 | struct cfdriver ukspan_cd = { |
| 163 | NULL((void *)0), "ukspan", DV_DULL |
| 164 | }; |
| 165 | |
| 166 | const struct cfattach ukspan_ca = { |
| 167 | sizeof(struct ukspan_softc), ukspan_match, ukspan_attach, |
| 168 | ukspan_detach |
| 169 | }; |
| 170 | |
| 171 | static const struct usb_devno ukspan_devs[] = { |
| 172 | { USB_VENDOR_KEYSPAN0x06cd, USB_PRODUCT_KEYSPAN_USA19HS0x0121 }, |
| 173 | }; |
| 174 | |
| 175 | static const struct ucom_methods ukspan_methods = { |
| 176 | .ucom_get_status = ukspan_get_status, |
| 177 | .ucom_set = ukspan_set, |
| 178 | .ucom_param = ukspan_param, |
| 179 | .ucom_ioctl = NULL((void *)0), |
| 180 | .ucom_open = ukspan_open, |
| 181 | .ucom_close = ukspan_close, |
| 182 | .ucom_read = NULL((void *)0), |
| 183 | .ucom_write = NULL((void *)0), |
| 184 | }; |
| 185 | |
| 186 | int |
| 187 | ukspan_match(struct device *parent, void *match, void *aux) |
| 188 | { |
| 189 | struct usb_attach_arg *uaa = aux; |
| 190 | |
| 191 | if (uaa->iface != NULL((void *)0)) |
| 192 | return UMATCH_NONE0; |
| 193 | |
| 194 | int found = usb_lookup(ukspan_devs, uaa->vendor, uaa->product)usbd_match_device((const struct usb_devno *)(ukspan_devs), sizeof (ukspan_devs) / sizeof ((ukspan_devs)[0]), sizeof ((ukspan_devs )[0]), (uaa->vendor), (uaa->product)) != NULL((void *)0); |
| 195 | return found ? UMATCH_VENDOR_PRODUCT13 : UMATCH_NONE0; |
| 196 | } |
| 197 | |
| 198 | void |
| 199 | ukspan_attach(struct device *parent, struct device *self, void *aux) |
| 200 | { |
| 201 | struct ukspan_softc *sc = (struct ukspan_softc *)self; |
| 202 | struct usb_attach_arg *uaa = aux; |
| 203 | struct usbd_device *dev = uaa->device; |
| 204 | struct ucom_attach_args uca = {0}; |
| 205 | usb_endpoint_descriptor_t *ed; |
| 206 | const char *devname = sc->sc_dev.dv_xname; |
| 207 | usbd_status err; |
| 208 | int t1, t2, t3, t4; |
| 209 | |
| 210 | DPRINTF("attach\n")do { ; } while (0); |
| 211 | |
| 212 | sc->udev = dev; |
| 213 | sc->cin_pipe = sc->cout_pipe = NULL((void *)0); |
| 214 | sc->ixfer = sc->oxfer = NULL((void *)0); |
| 215 | sc->ucom_dev = NULL((void *)0); |
| 216 | |
| 217 | /* |
| 218 | * Switch to configuration 1 where the transfer mode of the input |
| 219 | * endpoints is bulk instead of interrupt, as ucom expects |
| 220 | */ |
| 221 | err = usbd_set_config_index(sc->udev, UKSPAN_CONFIG_IDX1, 1); |
| 222 | if (err) { |
| 223 | printf("%s: set config failed\n", devname); |
| 224 | goto fail; |
| 225 | } |
| 226 | |
| 227 | err = usbd_device2interface_handle(sc->udev, UKSPAN_IFACE_IDX0, |
| 228 | &sc->iface); |
| 229 | if (err) { |
| 230 | printf("%s: get interface failed\n", devname); |
| 231 | goto fail; |
| 232 | } |
| 233 | |
| 234 | ed = usbd_get_endpoint_descriptor(sc->iface, UKSPAN_EA_BULKIN(0x80 | 1)); |
| 235 | t1 = UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03); |
| 236 | uca.ibufsize = UGETW(ed->wMaxPacketSize)(*(u_int16_t *)(ed->wMaxPacketSize)); |
| 237 | uca.bulkin = UKSPAN_EA_BULKIN(0x80 | 1); |
| 238 | |
| 239 | ed = usbd_get_endpoint_descriptor(sc->iface, UKSPAN_EA_BULKOUT(0x00 | 1)); |
| 240 | t2 = UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03); |
| 241 | uca.obufsize = UGETW(ed->wMaxPacketSize)(*(u_int16_t *)(ed->wMaxPacketSize)); |
| 242 | uca.bulkout = UKSPAN_EA_BULKOUT(0x00 | 1); |
| 243 | |
| 244 | ed = usbd_get_endpoint_descriptor(sc->iface, UKSPAN_EA_CONFIGIN(0x80 | 2)); |
| 245 | t3 = UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03); |
| 246 | if (UGETW(ed->wMaxPacketSize)(*(u_int16_t *)(ed->wMaxPacketSize)) < sizeof(struct ukspan_smsg)) { |
| 247 | printf("%s: in config packet size too small\n", devname); |
| 248 | goto fail; |
| 249 | } |
| 250 | |
| 251 | ed = usbd_get_endpoint_descriptor(sc->iface, UKSPAN_EA_CONFIGOUT(0x00 | 2)); |
| 252 | t4 = UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03); |
| 253 | if (UGETW(ed->wMaxPacketSize)(*(u_int16_t *)(ed->wMaxPacketSize)) < sizeof(struct ukspan_cmsg)) { |
| 254 | printf("%s: out config packet size too small\n", devname); |
| 255 | goto fail; |
| 256 | } |
| 257 | |
| 258 | if (t1 != UE_BULK0x02 || t2 != UE_BULK0x02 || t3 != UE_BULK0x02 || t4 != UE_BULK0x02) { |
| 259 | printf("%s: unexpected xfertypes %x %x %x %x != %x\n", devname, |
| 260 | t1, t2, t3, t4, UE_BULK0x02); |
| 261 | goto fail; |
| 262 | } |
| 263 | |
| 264 | /* Resource acquisition starts here */ |
| 265 | err = usbd_open_pipe(sc->iface, UKSPAN_EA_CONFIGOUT(0x00 | 2), USBD_EXCLUSIVE_USE0x01, |
| 266 | &sc->cout_pipe); |
| 267 | if (err) { |
| 268 | printf("%s: failed to create control out pipe\n", devname); |
| 269 | goto fail; |
| 270 | } |
| 271 | |
| 272 | err = usbd_open_pipe(sc->iface, UKSPAN_EA_CONFIGIN(0x80 | 2), USBD_EXCLUSIVE_USE0x01, |
| 273 | &sc->cin_pipe); |
| 274 | if (err) { |
| 275 | printf("%s: failed to create control out pipe\n", devname); |
| 276 | goto fail; |
| 277 | } |
| 278 | |
| 279 | sc->ixfer = usbd_alloc_xfer(sc->udev); |
| 280 | sc->oxfer = usbd_alloc_xfer(sc->udev); |
| 281 | if (!sc->ixfer || !sc->oxfer) { |
| 282 | printf("%s: failed to allocate xfers\n", devname); |
| 283 | goto fail; |
| 284 | } |
| 285 | |
| 286 | usbd_setup_xfer(sc->ixfer, sc->cin_pipe, sc, &sc->smsg, |
| 287 | sizeof(sc->smsg), 0, USBD_NO_TIMEOUT0, ukspan_incb); |
| 288 | err = usbd_transfer(sc->ixfer); |
| 289 | if (err && err != USBD_IN_PROGRESS) { |
| 290 | printf("%s: failed to start ixfer\n", devname); |
| 291 | goto fail; |
| 292 | } |
| 293 | |
| 294 | uca.portno = UCOM_UNK_PORTNO-1; |
| 295 | uca.ibufsizepad = uca.ibufsize; |
| 296 | uca.opkthdrlen = 0; |
| 297 | uca.device = dev; |
| 298 | uca.iface = sc->iface; |
| 299 | uca.methods = &ukspan_methods; |
| 300 | uca.arg = sc; |
| 301 | uca.info = NULL((void *)0); |
| 302 | |
| 303 | sc->ucom_dev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); |
| 304 | |
| 305 | DPRINTF("attach done\n")do { ; } while (0); |
| 306 | |
| 307 | return; |
| 308 | fail: |
| 309 | ukspan_destroy(sc); |
| 310 | usbd_deactivate(sc->udev); |
| 311 | } |
| 312 | |
| 313 | int |
| 314 | ukspan_detach(struct device *self, int flags) |
| 315 | { |
| 316 | struct ukspan_softc *sc = (struct ukspan_softc *)self; |
| 317 | DPRINTF("detach\n")do { ; } while (0); |
| 318 | |
| 319 | ukspan_destroy(sc); |
| 320 | |
| 321 | if (sc->ucom_dev) { |
| 322 | config_detach(sc->ucom_dev, flags); |
| 323 | sc->ucom_dev = NULL((void *)0); |
| 324 | } |
| 325 | return 0; |
| 326 | } |
| 327 | |
| 328 | void |
| 329 | ukspan_outcb(struct usbd_xfer *xfer, void *priv, usbd_status status) |
| 330 | { |
| 331 | struct ukspan_softc *sc = priv; |
| 332 | const char *devname = sc->sc_dev.dv_xname; |
| 333 | |
| 334 | DPRINTF("outcb\n")do { ; } while (0); |
| 335 | |
| 336 | if (usbd_is_dying(sc->udev)) { |
| 337 | DPRINTF("usb dying\n")do { ; } while (0); |
| 338 | return; |
| 339 | } |
| 340 | if (status != USBD_NORMAL_COMPLETION) { |
| 341 | printf("%s: oxfer failed\n", devname); |
| 342 | return; |
| 343 | } |
| 344 | } |
| 345 | |
| 346 | void |
| 347 | ukspan_incb(struct usbd_xfer *xfer, void *priv, usbd_status status) |
| 348 | { |
| 349 | struct ukspan_softc *sc = priv; |
| 350 | const char *devname = sc->sc_dev.dv_xname; |
| 351 | const struct ukspan_smsg *smsg = &sc->smsg; |
| 352 | usbd_status err; |
| 353 | u_int32_t len; |
| 354 | |
| 355 | DPRINTF("incb\n")do { ; } while (0); |
| 356 | |
| 357 | if (usbd_is_dying(sc->udev)) { |
| 358 | printf("%s: usb dying\n", devname); |
| 359 | return; |
| 360 | } |
| 361 | if (!sc->cin_pipe || !sc->ixfer) { |
| 362 | printf("%s: no cin_pipe, but not dying?\n", devname); |
| 363 | return; |
| 364 | } |
| 365 | if (status != USBD_NORMAL_COMPLETION) { |
| 366 | if (status != USBD_NOT_STARTED && status != USBD_CANCELLED) |
| 367 | printf("%s: ixfer failed\n", devname); |
| 368 | return; |
| 369 | } |
| 370 | |
| 371 | usbd_get_xfer_status(xfer, NULL((void *)0), NULL((void *)0), &len, NULL((void *)0)); |
| 372 | if (len < sizeof(struct ukspan_smsg)) { |
| 373 | printf("%s: short read\n", devname); |
| 374 | return; |
| 375 | } |
| 376 | |
| 377 | /* The device provides the actual MSR register */ |
| 378 | sc->msr = smsg->msr; |
| 379 | /* But not LSR... */ |
| 380 | sc->lsr = (smsg->rxoverrun ? ULSR_OE0x02 : 0) | |
| 381 | (smsg->rxparity ? ULSR_PE0x04 : 0) | |
| 382 | (smsg->rxframe ? ULSR_FE0x08 : 0) | |
| 383 | (smsg->rxbreak ? ULSR_BI0x10 : 0); |
| 384 | ucom_status_change((struct ucom_softc *)sc->ucom_dev); |
| 385 | |
| 386 | usbd_setup_xfer(sc->ixfer, sc->cin_pipe, sc, &sc->smsg, |
| 387 | sizeof(sc->smsg), USBD_SHORT_XFER_OK0x04, USBD_NO_TIMEOUT0, |
| 388 | ukspan_incb); |
| 389 | err = usbd_transfer(sc->ixfer); |
| 390 | if (err && err != USBD_IN_PROGRESS) |
| 391 | printf("%s: usbd transfer failed\n", devname); |
| 392 | } |
| 393 | |
| 394 | void |
| 395 | ukspan_get_status(void *addr, int portno, u_char *lsr, u_char *msr) |
| 396 | { |
| 397 | struct ukspan_softc *sc = addr; |
| 398 | DPRINTF("get status\n")do { ; } while (0); |
| 399 | if (lsr) |
| 400 | *lsr = sc->lsr; |
| 401 | if (msr) |
| 402 | *msr = sc->msr; |
| 403 | } |
| 404 | |
| 405 | void |
| 406 | ukspan_cmsg_init(bool_Bool opening, struct ukspan_cmsg *omsg) |
| 407 | { |
| 408 | bzero(omsg, sizeof(*omsg))__builtin_bzero((omsg), (sizeof(*omsg))); |
| 409 | |
| 410 | omsg->xonchar = 17; |
| 411 | omsg->xoffchar = 19; |
| 412 | |
| 413 | omsg->rxforwardingchars = 16; |
| 414 | omsg->rxforwardingtimeoutms = 16; |
| 415 | omsg->txacksetting = 0; |
| 416 | omsg->txbreak = 0; |
| 417 | if (opening) { |
| 418 | omsg->portenabled = 1; |
| 419 | omsg->rxflush = 1; |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | int |
| 424 | ukspan_cmsg_send(struct ukspan_softc *sc) |
| 425 | { |
| 426 | const char *devname = sc->sc_dev.dv_xname; |
| 427 | usbd_status err; |
| 428 | |
| 429 | usbd_setup_xfer(sc->oxfer, sc->cout_pipe, sc, &sc->cmsg, |
| 430 | sizeof(sc->cmsg), USBD_SYNCHRONOUS0x02, USBD_NO_TIMEOUT0, ukspan_outcb); |
| 431 | err = usbd_transfer(sc->oxfer); |
| 432 | if (err != USBD_NORMAL_COMPLETION) { |
| 433 | printf("%s: control xfer failed\n", devname); |
| 434 | return EIO5; |
| 435 | } |
| 436 | return 0; |
| 437 | } |
| 438 | |
| 439 | void |
| 440 | ukspan_set(void *addr, int portno, int reg, int onoff) |
| 441 | { |
| 442 | struct ukspan_softc *sc = addr; |
| 443 | const char *devname = sc->sc_dev.dv_xname; |
| 444 | DPRINTF("set %#x = %#x\n", reg, onoff)do { ; } while (0); |
| 445 | int flag = !!onoff; |
| 446 | switch (reg) { |
| 447 | case UCOM_SET_DTR1: |
| 448 | sc->cmsg.setdtr = 1; |
| 449 | sc->cmsg.dtr = flag; |
| 450 | break; |
| 451 | case UCOM_SET_RTS2: |
| 452 | sc->cmsg.setrts = 1; |
| 453 | sc->cmsg.rts = flag; |
| 454 | break; |
| 455 | case UCOM_SET_BREAK3: |
| 456 | sc->cmsg.txbreak = flag; |
| 457 | break; |
| 458 | default: |
| 459 | printf("%s: unhandled reg %#x\n", devname, reg); |
| 460 | return; |
| 461 | } |
| 462 | ukspan_cmsg_send(sc); |
| 463 | } |
| 464 | |
| 465 | int |
| 466 | ukspan_param(void *addr, int portno, struct termios *ti) |
| 467 | { |
| 468 | struct ukspan_softc *sc = addr; |
| 469 | const char *devname = sc->sc_dev.dv_xname; |
| 470 | struct ukspan_cmsg *cmsg = &sc->cmsg; |
| 471 | speed_t baud; |
| 472 | tcflag_t cflag; |
| 473 | u_int32_t div; |
| 474 | u_int8_t lcr; |
| 475 | |
| 476 | DPRINTF("param: %#x %#x %#x\n", ti->c_ospeed, ti->c_cflag, ti->c_iflag)do { ; } while (0); |
| 477 | |
| 478 | /* Set baud */ |
| 479 | div = 1; |
Value stored to 'div' is never read | |
| 480 | baud = ti->c_ospeed; |
| 481 | switch (baud) { |
| 482 | case B300300: |
| 483 | case B600600: |
| 484 | case B12001200: |
| 485 | case B24002400: |
| 486 | case B48004800: |
| 487 | case B96009600: |
| 488 | case B1920019200: |
| 489 | case B3840038400: |
| 490 | case B5760057600: |
| 491 | case B115200115200: |
| 492 | case B230400230400: |
| 493 | div = UKSPAN_CLOCK14769231 / (baud * 16); |
| 494 | break; |
| 495 | default: |
| 496 | printf("%s: unexpected baud: %d\n", devname, baud); |
| 497 | return EINVAL22; |
| 498 | } |
| 499 | |
| 500 | cmsg->setclock = 1; |
| 501 | cmsg->baudlo = div & 0xff; |
| 502 | cmsg->baudhi = div >> 8; |
| 503 | |
| 504 | cmsg->setrxmode = 1; |
| 505 | cmsg->settxmode = 1; |
| 506 | if (baud > 57600) |
| 507 | cmsg->rxmode = cmsg->txmode = UKSPAN_MAGIC0x2; |
| 508 | else |
| 509 | cmsg->rxmode = cmsg->txmode = 0; |
| 510 | |
| 511 | /* Set parity, data, and stop bits */ |
| 512 | cflag = ti->c_cflag; |
| 513 | if ((cflag & CIGNORE0x00000001) == 0) { |
| 514 | if (cflag & PARENB0x00001000) |
| 515 | lcr = (cflag & PARODD0x00002000) ? UKSPAN_PARITY_ODD0x08 : |
| 516 | UKSPAN_PARITY_EVEN0x18; |
| 517 | else |
| 518 | lcr = UKSPAN_PARITY_NONE0x0; |
| 519 | switch (cflag & CSIZE0x00000300) { |
| 520 | case CS50x00000000: |
| 521 | lcr |= UKSPAN_DATA_50x0; |
| 522 | break; |
| 523 | case CS60x00000100: |
| 524 | lcr |= UKSPAN_DATA_60x1; |
| 525 | break; |
| 526 | case CS70x00000200: |
| 527 | lcr |= UKSPAN_DATA_70x2; |
| 528 | break; |
| 529 | case CS80x00000300: |
| 530 | lcr |= UKSPAN_DATA_80x3; |
| 531 | break; |
| 532 | } |
| 533 | |
| 534 | lcr |= (cflag & CSTOPB0x00000400) ? UKSPAN_STOP_20x4 : UKSPAN_STOP_10x0; |
| 535 | |
| 536 | cmsg->setlcr = 1; |
| 537 | cmsg->lcr = lcr; |
| 538 | } |
| 539 | |
| 540 | /* XXX flow control? */ |
| 541 | |
| 542 | ukspan_cmsg_send(sc); |
| 543 | return 0; |
| 544 | } |
| 545 | |
| 546 | int |
| 547 | ukspan_open(void *addr, int portno) |
| 548 | { |
| 549 | struct ukspan_softc *sc = addr; |
| 550 | int ret; |
| 551 | |
| 552 | DPRINTF("open\n")do { ; } while (0); |
| 553 | if (usbd_is_dying(sc->udev)) { |
| 554 | DPRINTF("usb dying\n")do { ; } while (0); |
| 555 | return ENXIO6; |
| 556 | } |
| 557 | |
| 558 | ukspan_cmsg_init(true1, &sc->cmsg); |
| 559 | ret = ukspan_cmsg_send(sc); |
| 560 | return ret; |
| 561 | } |
| 562 | |
| 563 | void |
| 564 | ukspan_close(void *addr, int portno) |
| 565 | { |
| 566 | struct ukspan_softc *sc = addr; |
| 567 | DPRINTF("close\n")do { ; } while (0); |
| 568 | if (usbd_is_dying(sc->udev)) { |
| 569 | DPRINTF("usb dying\n")do { ; } while (0); |
| 570 | return; |
| 571 | } |
| 572 | ukspan_cmsg_init(false0, &sc->cmsg); |
| 573 | ukspan_cmsg_send(sc); |
| 574 | } |
| 575 | |
| 576 | void |
| 577 | ukspan_destroy(struct ukspan_softc *sc) |
| 578 | { |
| 579 | DPRINTF("destroy\n")do { ; } while (0); |
| 580 | if (sc->cin_pipe) { |
| 581 | usbd_close_pipe(sc->cin_pipe); |
| 582 | sc->cin_pipe = NULL((void *)0); |
| 583 | } |
| 584 | if (sc->cout_pipe) { |
| 585 | usbd_close_pipe(sc->cout_pipe); |
| 586 | sc->cout_pipe = NULL((void *)0); |
| 587 | } |
| 588 | if (sc->oxfer) { |
| 589 | usbd_free_xfer(sc->oxfer); |
| 590 | sc->oxfer = NULL((void *)0); |
| 591 | } |
| 592 | if (sc->ixfer) { |
| 593 | usbd_free_xfer(sc->ixfer); |
| 594 | sc->ixfer = NULL((void *)0); |
| 595 | } |
| 596 | } |