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.3 2020/02/17 19:29:55 jasper 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 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 | } |