This source file includes following definitions.
- ucycom_match
- ucycom_attach
- ucycom_get_status
- ucycom_open
- ucycom_close
- ucycom_read
- ucycom_write
- ucycom_param
- ucycom_intr
- ucycom_set
- ucycom_get_cfg
- ucycom_detach
- ucycom_activate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/conf.h>
51 #include <sys/kernel.h>
52 #include <sys/malloc.h>
53 #include <sys/device.h>
54 #include <sys/sysctl.h>
55 #include <sys/tty.h>
56 #include <sys/file.h>
57 #include <sys/vnode.h>
58
59 #include <dev/usb/usb.h>
60 #include <dev/usb/usbhid.h>
61
62 #include <dev/usb/usbdi.h>
63 #include <dev/usb/usbdi_util.h>
64 #include <dev/usb/usbdevs.h>
65 #include <dev/usb/uhidev.h>
66 #include <dev/usb/hid.h>
67
68 #include <dev/usb/ucomvar.h>
69
70 #ifdef UCYCOM_DEBUG
71 #define DPRINTF(x) if (ucycomdebug) printf x
72 #define DPRINTFN(n, x) if (ucycomdebug > (n)) printf x
73 int ucycomdebug = 200;
74 #else
75 #define DPRINTF(x)
76 #define DPRINTFN(n,x)
77 #endif
78
79
80 #define UCYCOM_RESET 0x80
81 #define UCYCOM_PARITY_TYPE_MASK 0x20
82 #define UCYCOM_PARITY_ODD 0x20
83 #define UCYCOM_PARITY_EVEN 0x00
84 #define UCYCOM_PARITY_MASK 0x10
85 #define UCYCOM_PARITY_ON 0x10
86 #define UCYCOM_PARITY_OFF 0x00
87 #define UCYCOM_STOP_MASK 0x08
88 #define UCYCOM_STOP_BITS_2 0x08
89 #define UCYCOM_STOP_BITS_1 0x00
90 #define UCYCOM_DATA_MASK 0x03
91 #define UCYCOM_DATA_BITS_8 0x03
92 #define UCYCOM_DATA_BITS_7 0x02
93 #define UCYCOM_DATA_BITS_6 0x01
94 #define UCYCOM_DATA_BITS_5 0x00
95
96
97 #define UCYCOM_RI 0x80
98 #define UCYCOM_DCD 0x40
99 #define UCYCOM_DSR 0x20
100 #define UCYCOM_CTS 0x10
101 #define UCYCOM_ERROR 0x08
102 #define UCYCOM_LMASK 0x07
103
104
105 #define UCYCOM_DTR 0x20
106 #define UCYCOM_RTS 0x10
107 #define UCYCOM_ORESET 0x08
108
109 struct ucycom_softc {
110 struct uhidev sc_hdev;
111 usbd_device_handle sc_udev;
112
113
114 size_t sc_flen;
115 size_t sc_ilen;
116 size_t sc_olen;
117
118 uint8_t *sc_obuf;
119
120 uint8_t *sc_ibuf;
121 uint32_t sc_icnt;
122
123
124 uint32_t sc_baud;
125 uint8_t sc_cfg;
126 uint8_t sc_mcr;
127 uint8_t sc_msr;
128 uint8_t sc_newmsr;
129 int sc_swflags;
130
131 struct device *sc_subdev;
132
133
134 u_char sc_dying;
135 };
136
137
138 void ucycom_set(void *, int, int, int);
139 int ucycom_param(void *, int, struct termios *);
140 void ucycom_get_status(void *, int, u_char *, u_char *);
141 int ucycom_open(void *, int);
142 void ucycom_close(void *, int);
143 void ucycom_write(void *, int, u_char *, u_char *, u_int32_t *);
144 void ucycom_read(void *, int, u_char **, u_int32_t *);
145
146 struct ucom_methods ucycom_methods = {
147 NULL,
148 ucycom_set,
149 ucycom_param,
150 NULL,
151 ucycom_open,
152 ucycom_close,
153 ucycom_read,
154 ucycom_write,
155 };
156
157 void ucycom_intr(struct uhidev *, void *, u_int);
158
159 void ucycom_get_cfg(struct ucycom_softc *);
160
161 const struct usb_devno ucycom_devs[] = {
162 { USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_USBRS232 },
163 { USB_VENDOR_DELORME, USB_PRODUCT_DELORME_EMUSB },
164 { USB_VENDOR_DELORME, USB_PRODUCT_DELORME_EMLT20 },
165 };
166 #define ucycom_lookup(v, p) usb_lookup(ucycom_devs, v, p)
167
168 int ucycom_match(struct device *, void *, void *);
169 void ucycom_attach(struct device *, struct device *, void *);
170 int ucycom_detach(struct device *, int);
171 int ucycom_activate(struct device *, enum devact);
172
173 struct cfdriver ucycom_cd = {
174 NULL, "ucycom", DV_DULL
175 };
176
177 const struct cfattach ucycom_ca = {
178 sizeof(struct ucycom_softc),
179 ucycom_match,
180 ucycom_attach,
181 ucycom_detach,
182 ucycom_activate,
183 };
184
185 int
186 ucycom_match(struct device *parent, void *match, void *aux)
187 {
188 struct uhidev_attach_arg *uha = aux;
189
190 DPRINTF(("ucycom match\n"));
191 return (ucycom_lookup(uha->uaa->vendor, uha->uaa->product) != NULL ?
192 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
193 }
194
195 void
196 ucycom_attach(struct device *parent, struct device *self, void *aux)
197 {
198 struct ucycom_softc *sc = (struct ucycom_softc *)self;
199 struct usb_attach_arg *uaa = aux;
200 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
201 usbd_device_handle dev = uha->parent->sc_udev;
202 struct ucom_attach_args uca;
203 int size, repid, err;
204 void *desc;
205
206 sc->sc_hdev.sc_intr = ucycom_intr;
207 sc->sc_hdev.sc_parent = uha->parent;
208 sc->sc_hdev.sc_report_id = uha->reportid;
209
210 uhidev_get_report_desc(uha->parent, &desc, &size);
211 repid = uha->reportid;
212 sc->sc_ilen = hid_report_size(desc, size, hid_input, repid);
213 sc->sc_olen = hid_report_size(desc, size, hid_output, repid);
214 sc->sc_flen = hid_report_size(desc, size, hid_feature, repid);
215
216 DPRINTF(("ucycom_open: olen %d ilen %d flen %d\n", sc->sc_ilen,
217 sc->sc_olen, sc->sc_flen));
218
219 printf("\n");
220
221 sc->sc_udev = dev;
222
223 sc->sc_msr = sc->sc_mcr = 0;
224
225 err = uhidev_open(&sc->sc_hdev);
226 if (err) {
227 DPRINTF(("ucycom_open: uhidev_open %d\n", err));
228 return;
229 }
230
231 DPRINTF(("ucycom attach: sc %p opipe %p ipipe %p report_id %d\n",
232 sc, sc->sc_hdev.sc_parent->sc_opipe, sc->sc_hdev.sc_parent->sc_ipipe,
233 uha->reportid));
234
235
236 bzero(&uca, sizeof uca);
237 uca.bulkin = uca.bulkout = -1;
238 uca.uhidev = sc->sc_hdev.sc_parent;
239 uca.ibufsize = sc->sc_ilen - 1;
240 uca.obufsize = sc->sc_olen - 1;
241 uca.ibufsizepad = 1;
242 uca.opkthdrlen = 0;
243 uca.device = uaa->device;
244 uca.iface = uaa->iface;
245 uca.methods = &ucycom_methods;
246 uca.arg = sc;
247 uca.info = NULL;
248
249 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
250 &sc->sc_hdev.sc_dev);
251
252 sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
253 DPRINTF(("ucycom_attach: complete %p\n", sc->sc_subdev));
254 }
255
256 void
257 ucycom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
258 {
259 struct ucycom_softc *sc = addr;
260
261 DPRINTF(("ucycom_get_status:\n"));
262
263 #if 0
264 if (lsr != NULL)
265 *lsr = sc->sc_lsr;
266 #endif
267 if (msr != NULL)
268 *msr = sc->sc_msr;
269 }
270
271 int
272 ucycom_open(void *addr, int portno)
273 {
274 struct ucycom_softc *sc = addr;
275 struct termios t;
276 int err;
277
278 DPRINTF(("ucycom_open: complete\n"));
279
280 if (sc->sc_dying)
281 return (EIO);
282
283
284 sc->sc_obuf = malloc(sc->sc_olen, M_USBDEV, M_WAITOK);
285
286
287 sc->sc_ibuf = malloc(sc->sc_ilen, M_USBDEV, M_WAITOK);
288
289 DPRINTF(("ucycom_open: sc->sc_ibuf=%p sc->sc_obuf=%p \n",
290 sc->sc_ibuf, sc->sc_obuf));
291
292 t.c_ospeed = 9600;
293 t.c_cflag = CSTOPB | CS8;
294 (void)ucycom_param(sc, portno, &t);
295
296 sc->sc_mcr = UCYCOM_DTR | UCYCOM_RTS;
297 memset(sc->sc_obuf, 0, sc->sc_olen);
298 sc->sc_obuf[0] = sc->sc_mcr;
299 err = uhidev_write(sc->sc_hdev.sc_parent, sc->sc_obuf, sc->sc_olen);
300 if (err) {
301 DPRINTF(("ucycom_open: set RTS err=%d\n", err));
302 return (EIO);
303 }
304
305 return (0);
306 }
307
308 void
309 ucycom_close(void *addr, int portno)
310 {
311 struct ucycom_softc *sc = addr;
312 int s;
313
314 if (sc->sc_dying)
315 return;
316
317 s = splusb();
318 if (sc->sc_obuf != NULL) {
319 free(sc->sc_obuf, M_USBDEV);
320 sc->sc_obuf = NULL;
321 }
322 if (sc->sc_ibuf != NULL) {
323 free(sc->sc_ibuf, M_USBDEV);
324 sc->sc_ibuf = NULL;
325 }
326 splx(s);
327 }
328
329 void
330 ucycom_read(void *addr, int portno, u_char **ptr, u_int32_t *count)
331 {
332 struct ucycom_softc *sc = addr;
333
334 if (sc->sc_newmsr ^ sc->sc_msr) {
335 DPRINTF(("ucycom_read: msr %d new %d\n",
336 sc->sc_msr, sc->sc_newmsr));
337 sc->sc_msr = sc->sc_newmsr;
338 ucom_status_change((struct ucom_softc *)sc->sc_subdev);
339 }
340
341 DPRINTF(("ucycom_read: buf %p chars %d\n", sc->sc_ibuf, sc->sc_icnt));
342 *ptr = sc->sc_ibuf;
343 *count = sc->sc_icnt;
344 }
345
346 void
347 ucycom_write(void *addr, int portno, u_char *to, u_char *data, u_int32_t *cnt)
348 {
349 struct ucycom_softc *sc = addr;
350 u_int32_t len;
351 #ifdef UCYCOM_DEBUG
352 u_int32_t want = *cnt;
353 #endif
354
355
356
357
358
359
360
361
362 len = sc->sc_olen;
363 memset(to, 0, len);
364 switch (sc->sc_olen) {
365 case 8:
366 to[0] = *cnt | sc->sc_mcr;
367 memcpy(&to[1], data, *cnt);
368 DPRINTF(("ucycomstart(8): to[0] = %d | %d = %d\n",
369 *cnt, sc->sc_mcr, to[0]));
370 break;
371
372 case 32:
373 to[0] = sc->sc_mcr;
374 to[1] = *cnt;
375 memcpy(&to[2], data, *cnt);
376 DPRINTF(("ucycomstart(32): to[0] = %d\nto[1] = %d\n",
377 to[0], to[1]));
378 break;
379 }
380
381 #ifdef UCYCOM_DEBUG
382 if (ucycomdebug > 5) {
383 int i;
384
385 if (len != 0) {
386 DPRINTF(("ucycomstart: to[0..%d) =", len-1));
387 for (i = 0; i < len; i++)
388 DPRINTF((" %02x", to[i]));
389 DPRINTF(("\n"));
390 }
391 }
392 #endif
393 *cnt = len;
394
395 #if 0
396 ucycom_get_cfg(sc);
397 #endif
398 DPRINTFN(4,("ucycomstart: req %d chars did %d chars\n", want, len));
399 }
400
401 int
402 ucycom_param(void *addr, int portno, struct termios *t)
403 {
404 struct ucycom_softc *sc = addr;
405 uint8_t report[5];
406 uint32_t baud = 0;
407 uint8_t cfg;
408 int err;
409
410 if (sc->sc_dying)
411 return (EIO);
412
413 switch (t->c_ospeed) {
414 case 600:
415 case 1200:
416 case 2400:
417 case 4800:
418 case 9600:
419 case 19200:
420 case 38400:
421 case 57600:
422 #if 0
423
424
425
426
427 case 115200:
428 case 153600:
429 case 192000:
430 #endif
431 baud = t->c_ospeed;
432 break;
433 default:
434 return (EINVAL);
435 }
436
437 if (t->c_cflag & CIGNORE) {
438 cfg = sc->sc_cfg;
439 } else {
440 cfg = 0;
441 switch (t->c_cflag & CSIZE) {
442 case CS8:
443 cfg |= UCYCOM_DATA_BITS_8;
444 break;
445 case CS7:
446 cfg |= UCYCOM_DATA_BITS_7;
447 break;
448 case CS6:
449 cfg |= UCYCOM_DATA_BITS_6;
450 break;
451 case CS5:
452 cfg |= UCYCOM_DATA_BITS_5;
453 break;
454 default:
455 return (EINVAL);
456 }
457 cfg |= ISSET(t->c_cflag, CSTOPB) ?
458 UCYCOM_STOP_BITS_2 : UCYCOM_STOP_BITS_1;
459 cfg |= ISSET(t->c_cflag, PARENB) ?
460 UCYCOM_PARITY_ON : UCYCOM_PARITY_OFF;
461 cfg |= ISSET(t->c_cflag, PARODD) ?
462 UCYCOM_PARITY_ODD : UCYCOM_PARITY_EVEN;
463 }
464
465 DPRINTF(("ucycom_param: setting %d baud, %d-%c-%d (%d)\n", baud,
466 5 + (cfg & UCYCOM_DATA_MASK),
467 (cfg & UCYCOM_PARITY_MASK) ?
468 ((cfg & UCYCOM_PARITY_TYPE_MASK) ? 'O' : 'E') : 'N',
469 (cfg & UCYCOM_STOP_MASK) ? 2 : 1, cfg));
470
471 report[0] = baud & 0xff;
472 report[1] = (baud >> 8) & 0xff;
473 report[2] = (baud >> 16) & 0xff;
474 report[3] = (baud >> 24) & 0xff;
475 report[4] = cfg;
476 err = uhidev_set_report(&sc->sc_hdev, UHID_FEATURE_REPORT,
477 report, sc->sc_flen);
478 if (err != 0) {
479 DPRINTF(("ucycom_param: uhidev_set_report %d %s\n",
480 err, usbd_errstr(err)));
481 return EIO;
482 }
483 sc->sc_baud = baud;
484 return (err);
485 }
486
487 void
488 ucycom_intr(struct uhidev *addr, void *ibuf, u_int len)
489 {
490 extern void ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
491 struct ucycom_softc *sc = (struct ucycom_softc *)addr;
492 uint8_t *cp = ibuf;
493 int n, st, s;
494
495
496 if (sc->sc_ibuf == NULL)
497 return;
498
499
500 switch (len) {
501 case 8:
502 n = cp[0] & UCYCOM_LMASK;
503 st = cp[0] & ~UCYCOM_LMASK;
504 cp++;
505 break;
506
507 case 32:
508 st = cp[0];
509 n = cp[1];
510 cp += 2;
511 break;
512
513 default:
514 DPRINTFN(3,("ucycom_intr: Unknown input report length\n"));
515 return;
516 }
517
518 #ifdef UCYCOM_DEBUG
519 if (ucycomdebug > 5) {
520 u_int32_t i;
521
522 if (n != 0) {
523 DPRINTF(("ucycom_intr: ibuf[0..%d) =", n));
524 for (i = 0; i < n; i++)
525 DPRINTF((" %02x", cp[i]));
526 DPRINTF(("\n"));
527 }
528 }
529 #endif
530
531 if (n > 0 || st != sc->sc_msr) {
532 s = spltty();
533 sc->sc_newmsr = st;
534 bcopy(cp, sc->sc_ibuf, n);
535 sc->sc_icnt = n;
536 ucomreadcb(addr->sc_parent->sc_ixfer, sc->sc_subdev,
537 USBD_NORMAL_COMPLETION);
538 splx(s);
539 }
540 }
541
542 void
543 ucycom_set(void *addr, int portno, int reg, int onoff)
544 {
545 struct ucycom_softc *sc = addr;
546 int err;
547
548 switch (reg) {
549 case UCOM_SET_DTR:
550 if (onoff)
551 SET(sc->sc_mcr, UCYCOM_DTR);
552 else
553 CLR(sc->sc_mcr, UCYCOM_DTR);
554 break;
555 case UCOM_SET_RTS:
556 if (onoff)
557 SET(sc->sc_mcr, UCYCOM_RTS);
558 else
559 CLR(sc->sc_mcr, UCYCOM_RTS);
560 break;
561 case UCOM_SET_BREAK:
562 break;
563 }
564
565 memset(sc->sc_obuf, 0, sc->sc_olen);
566 sc->sc_obuf[0] = sc->sc_mcr;
567
568 err = uhidev_write(sc->sc_hdev.sc_parent, sc->sc_obuf, sc->sc_olen);
569 if (err)
570 DPRINTF(("ucycom_set_status: err=%d\n", err));
571 }
572
573 void
574 ucycom_get_cfg(struct ucycom_softc *sc)
575 {
576 int err, cfg, baud;
577 uint8_t report[5];
578
579 err = uhidev_get_report(&sc->sc_hdev, UHID_FEATURE_REPORT,
580 report, sc->sc_flen);
581 cfg = report[4];
582 baud = (report[3] << 24) + (report[2] << 16) + (report[1] << 8) + report[0];
583 DPRINTF(("ucycom_configure: device reports %d baud, %d-%c-%d (%d)\n", baud,
584 5 + (cfg & UCYCOM_DATA_MASK),
585 (cfg & UCYCOM_PARITY_MASK) ?
586 ((cfg & UCYCOM_PARITY_TYPE_MASK) ? 'O' : 'E') : 'N',
587 (cfg & UCYCOM_STOP_MASK) ? 2 : 1, cfg));
588 }
589
590 int
591 ucycom_detach(struct device *self, int flags)
592 {
593 struct ucycom_softc *sc = (struct ucycom_softc *)self;
594
595 DPRINTF(("ucycom_detach: sc=%p flags=%d\n", sc, flags));
596 sc->sc_dying = 1;
597 if (sc->sc_subdev != NULL) {
598 config_detach(sc->sc_subdev, flags);
599 sc->sc_subdev = NULL;
600 }
601 return (0);
602 }
603
604 int
605 ucycom_activate(struct device *self, enum devact act)
606 {
607 struct ucycom_softc *sc = (struct ucycom_softc *)self;
608 int rv = 0;
609
610 DPRINTFN(5,("ucycom_activate: %d\n", act));
611
612 switch (act) {
613 case DVACT_ACTIVATE:
614 break;
615
616 case DVACT_DEACTIVATE:
617 if (sc->sc_subdev != NULL)
618 rv = config_deactivate(sc->sc_subdev);
619 sc->sc_dying = 1;
620 break;
621 }
622 return (rv);
623 }