3 4/*- 5 * Copyright (c) 2003 Scott Long 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31/* 32 * Driver for the MCT (Magic Control Technology) USB-RS232 Converter. 33 * Based on the superb documentation from the linux mct_u232 driver by 34 * Wolfgang Grandeggar <wolfgang@cec.ch>. 35 * This device smells a lot like the Belkin F5U103, except that it has 36 * suffered some mild brain-damage. This driver is based off of the ubsa.c 37 * driver from Alexander Kabaev <kan@FreeBSD.org>. Merging the two together 38 * might be useful, though the subtle differences might lead to lots of 39 * #ifdef's. 40 */ 41 42/* 43 * NOTE: all function names beginning like "umct_cfg_" can only 44 * be called from within the config thread function ! 45 */ 46 47#include <sys/stdint.h> 48#include <sys/stddef.h> 49#include <sys/param.h> 50#include <sys/queue.h> 51#include <sys/types.h> 52#include <sys/systm.h> 53#include <sys/kernel.h> 54#include <sys/bus.h> 55#include <sys/linker_set.h> 56#include <sys/module.h> 57#include <sys/lock.h> 58#include <sys/mutex.h> 59#include <sys/condvar.h> 60#include <sys/sysctl.h> 61#include <sys/sx.h> 62#include <sys/unistd.h> 63#include <sys/callout.h> 64#include <sys/malloc.h> 65#include <sys/priv.h> 66 67#include <dev/usb/usb.h> 68#include <dev/usb/usbdi.h> 69#include <dev/usb/usbdi_util.h> 70#include "usbdevs.h" 71 72#define USB_DEBUG_VAR usb_debug 73#include <dev/usb/usb_debug.h> 74#include <dev/usb/usb_process.h> 75 76#include <dev/usb/serial/usb_serial.h> 77 78/* The UMCT advertises the standard 8250 UART registers */ 79#define UMCT_GET_MSR 2 /* Get Modem Status Register */ 80#define UMCT_GET_MSR_SIZE 1 81#define UMCT_GET_LCR 6 /* Get Line Control Register */ 82#define UMCT_GET_LCR_SIZE 1 83#define UMCT_SET_BAUD 5 /* Set the Baud Rate Divisor */ 84#define UMCT_SET_BAUD_SIZE 4 85#define UMCT_SET_LCR 7 /* Set Line Control Register */ 86#define UMCT_SET_LCR_SIZE 1 87#define UMCT_SET_MCR 10 /* Set Modem Control Register */ 88#define UMCT_SET_MCR_SIZE 1 89 90#define UMCT_INTR_INTERVAL 100 91#define UMCT_IFACE_INDEX 0 92#define UMCT_CONFIG_INDEX 0 93 94enum { 95 UMCT_BULK_DT_WR, 96 UMCT_BULK_DT_RD, 97 UMCT_INTR_DT_RD, 98 UMCT_N_TRANSFER, 99}; 100 101struct umct_softc { 102 struct ucom_super_softc sc_super_ucom; 103 struct ucom_softc sc_ucom; 104 105 struct usb_device *sc_udev; 106 struct usb_xfer *sc_xfer[UMCT_N_TRANSFER]; 107 struct mtx sc_mtx; 108 109 uint32_t sc_unit; 110 111 uint16_t sc_obufsize; 112 113 uint8_t sc_lsr; 114 uint8_t sc_msr; 115 uint8_t sc_lcr; 116 uint8_t sc_mcr; 117 uint8_t sc_iface_no; 118 uint8_t sc_name[16]; 119}; 120 121/* prototypes */ 122 123static device_probe_t umct_probe; 124static device_attach_t umct_attach; 125static device_detach_t umct_detach; 126 127static usb_callback_t umct_intr_callback; 128static usb_callback_t umct_write_callback; 129static usb_callback_t umct_read_callback; 130 131static void umct_cfg_do_request(struct umct_softc *sc, uint8_t request, 132 uint16_t len, uint32_t value); 133static void umct_cfg_get_status(struct ucom_softc *, uint8_t *, 134 uint8_t *); 135static void umct_cfg_set_break(struct ucom_softc *, uint8_t); 136static void umct_cfg_set_dtr(struct ucom_softc *, uint8_t); 137static void umct_cfg_set_rts(struct ucom_softc *, uint8_t); 138static uint8_t umct_calc_baud(uint32_t); 139static int umct_pre_param(struct ucom_softc *, struct termios *); 140static void umct_cfg_param(struct ucom_softc *, struct termios *); 141static void umct_start_read(struct ucom_softc *); 142static void umct_stop_read(struct ucom_softc *); 143static void umct_start_write(struct ucom_softc *); 144static void umct_stop_write(struct ucom_softc *);
| 3 4/*- 5 * Copyright (c) 2003 Scott Long 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31/* 32 * Driver for the MCT (Magic Control Technology) USB-RS232 Converter. 33 * Based on the superb documentation from the linux mct_u232 driver by 34 * Wolfgang Grandeggar <wolfgang@cec.ch>. 35 * This device smells a lot like the Belkin F5U103, except that it has 36 * suffered some mild brain-damage. This driver is based off of the ubsa.c 37 * driver from Alexander Kabaev <kan@FreeBSD.org>. Merging the two together 38 * might be useful, though the subtle differences might lead to lots of 39 * #ifdef's. 40 */ 41 42/* 43 * NOTE: all function names beginning like "umct_cfg_" can only 44 * be called from within the config thread function ! 45 */ 46 47#include <sys/stdint.h> 48#include <sys/stddef.h> 49#include <sys/param.h> 50#include <sys/queue.h> 51#include <sys/types.h> 52#include <sys/systm.h> 53#include <sys/kernel.h> 54#include <sys/bus.h> 55#include <sys/linker_set.h> 56#include <sys/module.h> 57#include <sys/lock.h> 58#include <sys/mutex.h> 59#include <sys/condvar.h> 60#include <sys/sysctl.h> 61#include <sys/sx.h> 62#include <sys/unistd.h> 63#include <sys/callout.h> 64#include <sys/malloc.h> 65#include <sys/priv.h> 66 67#include <dev/usb/usb.h> 68#include <dev/usb/usbdi.h> 69#include <dev/usb/usbdi_util.h> 70#include "usbdevs.h" 71 72#define USB_DEBUG_VAR usb_debug 73#include <dev/usb/usb_debug.h> 74#include <dev/usb/usb_process.h> 75 76#include <dev/usb/serial/usb_serial.h> 77 78/* The UMCT advertises the standard 8250 UART registers */ 79#define UMCT_GET_MSR 2 /* Get Modem Status Register */ 80#define UMCT_GET_MSR_SIZE 1 81#define UMCT_GET_LCR 6 /* Get Line Control Register */ 82#define UMCT_GET_LCR_SIZE 1 83#define UMCT_SET_BAUD 5 /* Set the Baud Rate Divisor */ 84#define UMCT_SET_BAUD_SIZE 4 85#define UMCT_SET_LCR 7 /* Set Line Control Register */ 86#define UMCT_SET_LCR_SIZE 1 87#define UMCT_SET_MCR 10 /* Set Modem Control Register */ 88#define UMCT_SET_MCR_SIZE 1 89 90#define UMCT_INTR_INTERVAL 100 91#define UMCT_IFACE_INDEX 0 92#define UMCT_CONFIG_INDEX 0 93 94enum { 95 UMCT_BULK_DT_WR, 96 UMCT_BULK_DT_RD, 97 UMCT_INTR_DT_RD, 98 UMCT_N_TRANSFER, 99}; 100 101struct umct_softc { 102 struct ucom_super_softc sc_super_ucom; 103 struct ucom_softc sc_ucom; 104 105 struct usb_device *sc_udev; 106 struct usb_xfer *sc_xfer[UMCT_N_TRANSFER]; 107 struct mtx sc_mtx; 108 109 uint32_t sc_unit; 110 111 uint16_t sc_obufsize; 112 113 uint8_t sc_lsr; 114 uint8_t sc_msr; 115 uint8_t sc_lcr; 116 uint8_t sc_mcr; 117 uint8_t sc_iface_no; 118 uint8_t sc_name[16]; 119}; 120 121/* prototypes */ 122 123static device_probe_t umct_probe; 124static device_attach_t umct_attach; 125static device_detach_t umct_detach; 126 127static usb_callback_t umct_intr_callback; 128static usb_callback_t umct_write_callback; 129static usb_callback_t umct_read_callback; 130 131static void umct_cfg_do_request(struct umct_softc *sc, uint8_t request, 132 uint16_t len, uint32_t value); 133static void umct_cfg_get_status(struct ucom_softc *, uint8_t *, 134 uint8_t *); 135static void umct_cfg_set_break(struct ucom_softc *, uint8_t); 136static void umct_cfg_set_dtr(struct ucom_softc *, uint8_t); 137static void umct_cfg_set_rts(struct ucom_softc *, uint8_t); 138static uint8_t umct_calc_baud(uint32_t); 139static int umct_pre_param(struct ucom_softc *, struct termios *); 140static void umct_cfg_param(struct ucom_softc *, struct termios *); 141static void umct_start_read(struct ucom_softc *); 142static void umct_stop_read(struct ucom_softc *); 143static void umct_start_write(struct ucom_softc *); 144static void umct_stop_write(struct ucom_softc *);
|
145 146static const struct usb_config umct_config[UMCT_N_TRANSFER] = { 147 148 [UMCT_BULK_DT_WR] = { 149 .type = UE_BULK, 150 .endpoint = UE_ADDR_ANY, 151 .direction = UE_DIR_OUT, 152 .bufsize = 0, /* use wMaxPacketSize */ 153 .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 154 .callback = &umct_write_callback, 155 }, 156 157 [UMCT_BULK_DT_RD] = { 158 .type = UE_INTERRUPT, 159 .endpoint = UE_ADDR_ANY, 160 .direction = UE_DIR_IN, 161 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 162 .bufsize = 0, /* use wMaxPacketSize */ 163 .callback = &umct_read_callback, 164 .ep_index = 0, /* first interrupt endpoint */ 165 }, 166 167 [UMCT_INTR_DT_RD] = { 168 .type = UE_INTERRUPT, 169 .endpoint = UE_ADDR_ANY, 170 .direction = UE_DIR_IN, 171 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 172 .bufsize = 0, /* use wMaxPacketSize */ 173 .callback = &umct_intr_callback, 174 .ep_index = 1, /* second interrupt endpoint */ 175 }, 176}; 177 178static const struct ucom_callback umct_callback = { 179 .ucom_cfg_get_status = &umct_cfg_get_status, 180 .ucom_cfg_set_dtr = &umct_cfg_set_dtr, 181 .ucom_cfg_set_rts = &umct_cfg_set_rts, 182 .ucom_cfg_set_break = &umct_cfg_set_break, 183 .ucom_cfg_param = &umct_cfg_param, 184 .ucom_pre_param = &umct_pre_param, 185 .ucom_start_read = &umct_start_read, 186 .ucom_stop_read = &umct_stop_read, 187 .ucom_start_write = &umct_start_write, 188 .ucom_stop_write = &umct_stop_write,
| 146 147static const struct usb_config umct_config[UMCT_N_TRANSFER] = { 148 149 [UMCT_BULK_DT_WR] = { 150 .type = UE_BULK, 151 .endpoint = UE_ADDR_ANY, 152 .direction = UE_DIR_OUT, 153 .bufsize = 0, /* use wMaxPacketSize */ 154 .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, 155 .callback = &umct_write_callback, 156 }, 157 158 [UMCT_BULK_DT_RD] = { 159 .type = UE_INTERRUPT, 160 .endpoint = UE_ADDR_ANY, 161 .direction = UE_DIR_IN, 162 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 163 .bufsize = 0, /* use wMaxPacketSize */ 164 .callback = &umct_read_callback, 165 .ep_index = 0, /* first interrupt endpoint */ 166 }, 167 168 [UMCT_INTR_DT_RD] = { 169 .type = UE_INTERRUPT, 170 .endpoint = UE_ADDR_ANY, 171 .direction = UE_DIR_IN, 172 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 173 .bufsize = 0, /* use wMaxPacketSize */ 174 .callback = &umct_intr_callback, 175 .ep_index = 1, /* second interrupt endpoint */ 176 }, 177}; 178 179static const struct ucom_callback umct_callback = { 180 .ucom_cfg_get_status = &umct_cfg_get_status, 181 .ucom_cfg_set_dtr = &umct_cfg_set_dtr, 182 .ucom_cfg_set_rts = &umct_cfg_set_rts, 183 .ucom_cfg_set_break = &umct_cfg_set_break, 184 .ucom_cfg_param = &umct_cfg_param, 185 .ucom_pre_param = &umct_pre_param, 186 .ucom_start_read = &umct_start_read, 187 .ucom_stop_read = &umct_stop_read, 188 .ucom_start_write = &umct_start_write, 189 .ucom_stop_write = &umct_stop_write,
|
189}; 190 191static const struct usb_device_id umct_devs[] = { 192 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0)}, 193 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232, 0)}, 194 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232, 0)}, 195 {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U109, 0)}, 196 {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U409, 0)}, 197}; 198 199static device_method_t umct_methods[] = { 200 DEVMETHOD(device_probe, umct_probe), 201 DEVMETHOD(device_attach, umct_attach), 202 DEVMETHOD(device_detach, umct_detach), 203 {0, 0} 204}; 205 206static devclass_t umct_devclass; 207 208static driver_t umct_driver = { 209 .name = "umct", 210 .methods = umct_methods, 211 .size = sizeof(struct umct_softc), 212}; 213 214DRIVER_MODULE(umct, uhub, umct_driver, umct_devclass, NULL, 0); 215MODULE_DEPEND(umct, ucom, 1, 1, 1); 216MODULE_DEPEND(umct, usb, 1, 1, 1); 217 218static int 219umct_probe(device_t dev) 220{ 221 struct usb_attach_arg *uaa = device_get_ivars(dev); 222 223 if (uaa->usb_mode != USB_MODE_HOST) { 224 return (ENXIO); 225 } 226 if (uaa->info.bConfigIndex != UMCT_CONFIG_INDEX) { 227 return (ENXIO); 228 } 229 if (uaa->info.bIfaceIndex != UMCT_IFACE_INDEX) { 230 return (ENXIO); 231 } 232 return (usbd_lookup_id_by_uaa(umct_devs, sizeof(umct_devs), uaa)); 233} 234 235static int 236umct_attach(device_t dev) 237{ 238 struct usb_attach_arg *uaa = device_get_ivars(dev); 239 struct umct_softc *sc = device_get_softc(dev); 240 int32_t error; 241 //uint16_t maxp; 242 uint8_t iface_index; 243 244 sc->sc_udev = uaa->device; 245 sc->sc_unit = device_get_unit(dev); 246 247 device_set_usb_desc(dev); 248 mtx_init(&sc->sc_mtx, "umct", NULL, MTX_DEF); 249 250 snprintf(sc->sc_name, sizeof(sc->sc_name), 251 "%s", device_get_nameunit(dev)); 252 253 sc->sc_iface_no = uaa->info.bIfaceNum; 254 255 iface_index = UMCT_IFACE_INDEX; 256 error = usbd_transfer_setup(uaa->device, &iface_index, 257 sc->sc_xfer, umct_config, UMCT_N_TRANSFER, sc, &sc->sc_mtx); 258 259 if (error) { 260 device_printf(dev, "allocating USB " 261 "transfers failed!\n"); 262 goto detach; 263 } 264 /* 265 * The real bulk-in endpoint is also marked as an interrupt. 266 * The only way to differentiate it from the real interrupt 267 * endpoint is to look at the wMaxPacketSize field. 268 */ 269#ifdef XXX 270 maxp = UGETW(sc->sc_xfer[UMCT_BULK_DT_RD]->endpoint->edesc->wMaxPacketSize); 271 if (maxp == 0x2) { 272 273 /* guessed wrong - switch around endpoints */ 274 275 struct usb_xfer *temp = sc->sc_xfer[UMCT_INTR_DT_RD]; 276 277 sc->sc_xfer[UMCT_INTR_DT_RD] = sc->sc_xfer[UMCT_BULK_DT_RD]; 278 sc->sc_xfer[UMCT_BULK_DT_RD] = temp; 279 280 sc->sc_xfer[UMCT_BULK_DT_RD]->callback = &umct_read_callback; 281 sc->sc_xfer[UMCT_INTR_DT_RD]->callback = &umct_intr_callback; 282 } 283#endif 284 sc->sc_obufsize = usbd_xfer_max_len(sc->sc_xfer[UMCT_BULK_DT_WR]); 285 286 if (uaa->info.idProduct == USB_PRODUCT_MCT_SITECOM_USB232) { 287 if (sc->sc_obufsize > 16) { 288 sc->sc_obufsize = 16; 289 } 290 } 291 error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 292 &umct_callback, &sc->sc_mtx); 293 if (error) { 294 goto detach; 295 } 296 return (0); /* success */ 297 298detach: 299 umct_detach(dev); 300 return (ENXIO); /* failure */ 301} 302 303static int 304umct_detach(device_t dev) 305{ 306 struct umct_softc *sc = device_get_softc(dev); 307 308 ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 309 usbd_transfer_unsetup(sc->sc_xfer, UMCT_N_TRANSFER); 310 mtx_destroy(&sc->sc_mtx); 311 312 return (0); 313} 314 315static void 316umct_cfg_do_request(struct umct_softc *sc, uint8_t request, 317 uint16_t len, uint32_t value) 318{ 319 struct usb_device_request req; 320 usb_error_t err; 321 uint8_t temp[4]; 322 323 if (len > 4) 324 len = 4; 325 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 326 req.bRequest = request; 327 USETW(req.wValue, 0); 328 req.wIndex[0] = sc->sc_iface_no; 329 req.wIndex[1] = 0; 330 USETW(req.wLength, len); 331 USETDW(temp, value); 332 333 err = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 334 &req, temp, 0, 1000); 335 if (err) { 336 DPRINTFN(0, "device request failed, err=%s " 337 "(ignored)\n", usbd_errstr(err)); 338 } 339 return; 340} 341 342static void 343umct_intr_callback(struct usb_xfer *xfer, usb_error_t error) 344{ 345 struct umct_softc *sc = usbd_xfer_softc(xfer); 346 struct usb_page_cache *pc; 347 uint8_t buf[2]; 348 int actlen; 349 350 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 351 352 switch (USB_GET_STATE(xfer)) { 353 case USB_ST_TRANSFERRED: 354 if (actlen < 2) { 355 DPRINTF("too short message\n"); 356 goto tr_setup; 357 } 358 pc = usbd_xfer_get_frame(xfer, 0); 359 usbd_copy_out(pc, 0, buf, sizeof(buf)); 360 361 sc->sc_msr = buf[0]; 362 sc->sc_lsr = buf[1]; 363 364 ucom_status_change(&sc->sc_ucom); 365 366 case USB_ST_SETUP: 367tr_setup: 368 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 369 usbd_transfer_submit(xfer); 370 return; 371 372 default: /* Error */ 373 if (error != USB_ERR_CANCELLED) { 374 /* try to clear stall first */ 375 usbd_xfer_set_stall(xfer); 376 goto tr_setup; 377 } 378 return; 379 } 380} 381 382static void 383umct_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 384{ 385 struct umct_softc *sc = ucom->sc_parent; 386 387 *lsr = sc->sc_lsr; 388 *msr = sc->sc_msr; 389} 390 391static void 392umct_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) 393{ 394 struct umct_softc *sc = ucom->sc_parent; 395 396 if (onoff) 397 sc->sc_lcr |= 0x40; 398 else 399 sc->sc_lcr &= ~0x40; 400 401 umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, sc->sc_lcr); 402} 403 404static void 405umct_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 406{ 407 struct umct_softc *sc = ucom->sc_parent; 408 409 if (onoff) 410 sc->sc_mcr |= 0x01; 411 else 412 sc->sc_mcr &= ~0x01; 413 414 umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr); 415} 416 417static void 418umct_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) 419{ 420 struct umct_softc *sc = ucom->sc_parent; 421 422 if (onoff) 423 sc->sc_mcr |= 0x02; 424 else 425 sc->sc_mcr &= ~0x02; 426 427 umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr); 428} 429 430static uint8_t 431umct_calc_baud(uint32_t baud) 432{ 433 switch (baud) { 434 case B300:return (0x1); 435 case B600: 436 return (0x2); 437 case B1200: 438 return (0x3); 439 case B2400: 440 return (0x4); 441 case B4800: 442 return (0x6); 443 case B9600: 444 return (0x8); 445 case B19200: 446 return (0x9); 447 case B38400: 448 return (0xa); 449 case B57600: 450 return (0xb); 451 case 115200: 452 return (0xc); 453 case B0: 454 default: 455 break; 456 } 457 return (0x0); 458} 459 460static int 461umct_pre_param(struct ucom_softc *ucom, struct termios *t) 462{ 463 return (0); /* we accept anything */ 464} 465 466static void 467umct_cfg_param(struct ucom_softc *ucom, struct termios *t) 468{ 469 struct umct_softc *sc = ucom->sc_parent; 470 uint32_t value; 471 472 value = umct_calc_baud(t->c_ospeed); 473 umct_cfg_do_request(sc, UMCT_SET_BAUD, UMCT_SET_BAUD_SIZE, value); 474 475 value = (sc->sc_lcr & 0x40); 476 477 switch (t->c_cflag & CSIZE) { 478 case CS5: 479 value |= 0x0; 480 break; 481 case CS6: 482 value |= 0x1; 483 break; 484 case CS7: 485 value |= 0x2; 486 break; 487 default: 488 case CS8: 489 value |= 0x3; 490 break; 491 } 492 493 value |= (t->c_cflag & CSTOPB) ? 0x4 : 0; 494 if (t->c_cflag & PARENB) { 495 value |= 0x8; 496 value |= (t->c_cflag & PARODD) ? 0x0 : 0x10; 497 } 498 /* 499 * XXX There doesn't seem to be a way to tell the device 500 * to use flow control. 501 */ 502 503 sc->sc_lcr = value; 504 umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, value); 505} 506 507static void 508umct_start_read(struct ucom_softc *ucom) 509{ 510 struct umct_softc *sc = ucom->sc_parent; 511 512 /* start interrupt endpoint */ 513 usbd_transfer_start(sc->sc_xfer[UMCT_INTR_DT_RD]); 514 515 /* start read endpoint */ 516 usbd_transfer_start(sc->sc_xfer[UMCT_BULK_DT_RD]); 517} 518 519static void 520umct_stop_read(struct ucom_softc *ucom) 521{ 522 struct umct_softc *sc = ucom->sc_parent; 523 524 /* stop interrupt endpoint */ 525 usbd_transfer_stop(sc->sc_xfer[UMCT_INTR_DT_RD]); 526 527 /* stop read endpoint */ 528 usbd_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_RD]); 529} 530 531static void 532umct_start_write(struct ucom_softc *ucom) 533{ 534 struct umct_softc *sc = ucom->sc_parent; 535 536 usbd_transfer_start(sc->sc_xfer[UMCT_BULK_DT_WR]); 537} 538 539static void 540umct_stop_write(struct ucom_softc *ucom) 541{ 542 struct umct_softc *sc = ucom->sc_parent; 543 544 usbd_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_WR]); 545} 546 547static void 548umct_write_callback(struct usb_xfer *xfer, usb_error_t error) 549{ 550 struct umct_softc *sc = usbd_xfer_softc(xfer); 551 struct usb_page_cache *pc; 552 uint32_t actlen; 553 554 switch (USB_GET_STATE(xfer)) { 555 case USB_ST_SETUP: 556 case USB_ST_TRANSFERRED: 557tr_setup: 558 pc = usbd_xfer_get_frame(xfer, 0); 559 if (ucom_get_data(&sc->sc_ucom, pc, 0, 560 sc->sc_obufsize, &actlen)) { 561 562 usbd_xfer_set_frame_len(xfer, 0, actlen); 563 usbd_transfer_submit(xfer); 564 } 565 return; 566 567 default: /* Error */ 568 if (error != USB_ERR_CANCELLED) { 569 /* try to clear stall first */ 570 usbd_xfer_set_stall(xfer); 571 goto tr_setup; 572 } 573 return; 574 } 575} 576 577static void 578umct_read_callback(struct usb_xfer *xfer, usb_error_t error) 579{ 580 struct umct_softc *sc = usbd_xfer_softc(xfer); 581 struct usb_page_cache *pc; 582 int actlen; 583 584 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 585 586 switch (USB_GET_STATE(xfer)) { 587 case USB_ST_TRANSFERRED: 588 pc = usbd_xfer_get_frame(xfer, 0); 589 ucom_put_data(&sc->sc_ucom, pc, 0, actlen); 590 591 case USB_ST_SETUP: 592tr_setup: 593 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 594 usbd_transfer_submit(xfer); 595 return; 596 597 default: /* Error */ 598 if (error != USB_ERR_CANCELLED) { 599 /* try to clear stall first */ 600 usbd_xfer_set_stall(xfer); 601 goto tr_setup; 602 } 603 return; 604 } 605}
| 191}; 192 193static const struct usb_device_id umct_devs[] = { 194 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0)}, 195 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232, 0)}, 196 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232, 0)}, 197 {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U109, 0)}, 198 {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U409, 0)}, 199}; 200 201static device_method_t umct_methods[] = { 202 DEVMETHOD(device_probe, umct_probe), 203 DEVMETHOD(device_attach, umct_attach), 204 DEVMETHOD(device_detach, umct_detach), 205 {0, 0} 206}; 207 208static devclass_t umct_devclass; 209 210static driver_t umct_driver = { 211 .name = "umct", 212 .methods = umct_methods, 213 .size = sizeof(struct umct_softc), 214}; 215 216DRIVER_MODULE(umct, uhub, umct_driver, umct_devclass, NULL, 0); 217MODULE_DEPEND(umct, ucom, 1, 1, 1); 218MODULE_DEPEND(umct, usb, 1, 1, 1); 219 220static int 221umct_probe(device_t dev) 222{ 223 struct usb_attach_arg *uaa = device_get_ivars(dev); 224 225 if (uaa->usb_mode != USB_MODE_HOST) { 226 return (ENXIO); 227 } 228 if (uaa->info.bConfigIndex != UMCT_CONFIG_INDEX) { 229 return (ENXIO); 230 } 231 if (uaa->info.bIfaceIndex != UMCT_IFACE_INDEX) { 232 return (ENXIO); 233 } 234 return (usbd_lookup_id_by_uaa(umct_devs, sizeof(umct_devs), uaa)); 235} 236 237static int 238umct_attach(device_t dev) 239{ 240 struct usb_attach_arg *uaa = device_get_ivars(dev); 241 struct umct_softc *sc = device_get_softc(dev); 242 int32_t error; 243 //uint16_t maxp; 244 uint8_t iface_index; 245 246 sc->sc_udev = uaa->device; 247 sc->sc_unit = device_get_unit(dev); 248 249 device_set_usb_desc(dev); 250 mtx_init(&sc->sc_mtx, "umct", NULL, MTX_DEF); 251 252 snprintf(sc->sc_name, sizeof(sc->sc_name), 253 "%s", device_get_nameunit(dev)); 254 255 sc->sc_iface_no = uaa->info.bIfaceNum; 256 257 iface_index = UMCT_IFACE_INDEX; 258 error = usbd_transfer_setup(uaa->device, &iface_index, 259 sc->sc_xfer, umct_config, UMCT_N_TRANSFER, sc, &sc->sc_mtx); 260 261 if (error) { 262 device_printf(dev, "allocating USB " 263 "transfers failed!\n"); 264 goto detach; 265 } 266 /* 267 * The real bulk-in endpoint is also marked as an interrupt. 268 * The only way to differentiate it from the real interrupt 269 * endpoint is to look at the wMaxPacketSize field. 270 */ 271#ifdef XXX 272 maxp = UGETW(sc->sc_xfer[UMCT_BULK_DT_RD]->endpoint->edesc->wMaxPacketSize); 273 if (maxp == 0x2) { 274 275 /* guessed wrong - switch around endpoints */ 276 277 struct usb_xfer *temp = sc->sc_xfer[UMCT_INTR_DT_RD]; 278 279 sc->sc_xfer[UMCT_INTR_DT_RD] = sc->sc_xfer[UMCT_BULK_DT_RD]; 280 sc->sc_xfer[UMCT_BULK_DT_RD] = temp; 281 282 sc->sc_xfer[UMCT_BULK_DT_RD]->callback = &umct_read_callback; 283 sc->sc_xfer[UMCT_INTR_DT_RD]->callback = &umct_intr_callback; 284 } 285#endif 286 sc->sc_obufsize = usbd_xfer_max_len(sc->sc_xfer[UMCT_BULK_DT_WR]); 287 288 if (uaa->info.idProduct == USB_PRODUCT_MCT_SITECOM_USB232) { 289 if (sc->sc_obufsize > 16) { 290 sc->sc_obufsize = 16; 291 } 292 } 293 error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 294 &umct_callback, &sc->sc_mtx); 295 if (error) { 296 goto detach; 297 } 298 return (0); /* success */ 299 300detach: 301 umct_detach(dev); 302 return (ENXIO); /* failure */ 303} 304 305static int 306umct_detach(device_t dev) 307{ 308 struct umct_softc *sc = device_get_softc(dev); 309 310 ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1); 311 usbd_transfer_unsetup(sc->sc_xfer, UMCT_N_TRANSFER); 312 mtx_destroy(&sc->sc_mtx); 313 314 return (0); 315} 316 317static void 318umct_cfg_do_request(struct umct_softc *sc, uint8_t request, 319 uint16_t len, uint32_t value) 320{ 321 struct usb_device_request req; 322 usb_error_t err; 323 uint8_t temp[4]; 324 325 if (len > 4) 326 len = 4; 327 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 328 req.bRequest = request; 329 USETW(req.wValue, 0); 330 req.wIndex[0] = sc->sc_iface_no; 331 req.wIndex[1] = 0; 332 USETW(req.wLength, len); 333 USETDW(temp, value); 334 335 err = ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 336 &req, temp, 0, 1000); 337 if (err) { 338 DPRINTFN(0, "device request failed, err=%s " 339 "(ignored)\n", usbd_errstr(err)); 340 } 341 return; 342} 343 344static void 345umct_intr_callback(struct usb_xfer *xfer, usb_error_t error) 346{ 347 struct umct_softc *sc = usbd_xfer_softc(xfer); 348 struct usb_page_cache *pc; 349 uint8_t buf[2]; 350 int actlen; 351 352 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 353 354 switch (USB_GET_STATE(xfer)) { 355 case USB_ST_TRANSFERRED: 356 if (actlen < 2) { 357 DPRINTF("too short message\n"); 358 goto tr_setup; 359 } 360 pc = usbd_xfer_get_frame(xfer, 0); 361 usbd_copy_out(pc, 0, buf, sizeof(buf)); 362 363 sc->sc_msr = buf[0]; 364 sc->sc_lsr = buf[1]; 365 366 ucom_status_change(&sc->sc_ucom); 367 368 case USB_ST_SETUP: 369tr_setup: 370 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 371 usbd_transfer_submit(xfer); 372 return; 373 374 default: /* Error */ 375 if (error != USB_ERR_CANCELLED) { 376 /* try to clear stall first */ 377 usbd_xfer_set_stall(xfer); 378 goto tr_setup; 379 } 380 return; 381 } 382} 383 384static void 385umct_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) 386{ 387 struct umct_softc *sc = ucom->sc_parent; 388 389 *lsr = sc->sc_lsr; 390 *msr = sc->sc_msr; 391} 392 393static void 394umct_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) 395{ 396 struct umct_softc *sc = ucom->sc_parent; 397 398 if (onoff) 399 sc->sc_lcr |= 0x40; 400 else 401 sc->sc_lcr &= ~0x40; 402 403 umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, sc->sc_lcr); 404} 405 406static void 407umct_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) 408{ 409 struct umct_softc *sc = ucom->sc_parent; 410 411 if (onoff) 412 sc->sc_mcr |= 0x01; 413 else 414 sc->sc_mcr &= ~0x01; 415 416 umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr); 417} 418 419static void 420umct_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) 421{ 422 struct umct_softc *sc = ucom->sc_parent; 423 424 if (onoff) 425 sc->sc_mcr |= 0x02; 426 else 427 sc->sc_mcr &= ~0x02; 428 429 umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr); 430} 431 432static uint8_t 433umct_calc_baud(uint32_t baud) 434{ 435 switch (baud) { 436 case B300:return (0x1); 437 case B600: 438 return (0x2); 439 case B1200: 440 return (0x3); 441 case B2400: 442 return (0x4); 443 case B4800: 444 return (0x6); 445 case B9600: 446 return (0x8); 447 case B19200: 448 return (0x9); 449 case B38400: 450 return (0xa); 451 case B57600: 452 return (0xb); 453 case 115200: 454 return (0xc); 455 case B0: 456 default: 457 break; 458 } 459 return (0x0); 460} 461 462static int 463umct_pre_param(struct ucom_softc *ucom, struct termios *t) 464{ 465 return (0); /* we accept anything */ 466} 467 468static void 469umct_cfg_param(struct ucom_softc *ucom, struct termios *t) 470{ 471 struct umct_softc *sc = ucom->sc_parent; 472 uint32_t value; 473 474 value = umct_calc_baud(t->c_ospeed); 475 umct_cfg_do_request(sc, UMCT_SET_BAUD, UMCT_SET_BAUD_SIZE, value); 476 477 value = (sc->sc_lcr & 0x40); 478 479 switch (t->c_cflag & CSIZE) { 480 case CS5: 481 value |= 0x0; 482 break; 483 case CS6: 484 value |= 0x1; 485 break; 486 case CS7: 487 value |= 0x2; 488 break; 489 default: 490 case CS8: 491 value |= 0x3; 492 break; 493 } 494 495 value |= (t->c_cflag & CSTOPB) ? 0x4 : 0; 496 if (t->c_cflag & PARENB) { 497 value |= 0x8; 498 value |= (t->c_cflag & PARODD) ? 0x0 : 0x10; 499 } 500 /* 501 * XXX There doesn't seem to be a way to tell the device 502 * to use flow control. 503 */ 504 505 sc->sc_lcr = value; 506 umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, value); 507} 508 509static void 510umct_start_read(struct ucom_softc *ucom) 511{ 512 struct umct_softc *sc = ucom->sc_parent; 513 514 /* start interrupt endpoint */ 515 usbd_transfer_start(sc->sc_xfer[UMCT_INTR_DT_RD]); 516 517 /* start read endpoint */ 518 usbd_transfer_start(sc->sc_xfer[UMCT_BULK_DT_RD]); 519} 520 521static void 522umct_stop_read(struct ucom_softc *ucom) 523{ 524 struct umct_softc *sc = ucom->sc_parent; 525 526 /* stop interrupt endpoint */ 527 usbd_transfer_stop(sc->sc_xfer[UMCT_INTR_DT_RD]); 528 529 /* stop read endpoint */ 530 usbd_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_RD]); 531} 532 533static void 534umct_start_write(struct ucom_softc *ucom) 535{ 536 struct umct_softc *sc = ucom->sc_parent; 537 538 usbd_transfer_start(sc->sc_xfer[UMCT_BULK_DT_WR]); 539} 540 541static void 542umct_stop_write(struct ucom_softc *ucom) 543{ 544 struct umct_softc *sc = ucom->sc_parent; 545 546 usbd_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_WR]); 547} 548 549static void 550umct_write_callback(struct usb_xfer *xfer, usb_error_t error) 551{ 552 struct umct_softc *sc = usbd_xfer_softc(xfer); 553 struct usb_page_cache *pc; 554 uint32_t actlen; 555 556 switch (USB_GET_STATE(xfer)) { 557 case USB_ST_SETUP: 558 case USB_ST_TRANSFERRED: 559tr_setup: 560 pc = usbd_xfer_get_frame(xfer, 0); 561 if (ucom_get_data(&sc->sc_ucom, pc, 0, 562 sc->sc_obufsize, &actlen)) { 563 564 usbd_xfer_set_frame_len(xfer, 0, actlen); 565 usbd_transfer_submit(xfer); 566 } 567 return; 568 569 default: /* Error */ 570 if (error != USB_ERR_CANCELLED) { 571 /* try to clear stall first */ 572 usbd_xfer_set_stall(xfer); 573 goto tr_setup; 574 } 575 return; 576 } 577} 578 579static void 580umct_read_callback(struct usb_xfer *xfer, usb_error_t error) 581{ 582 struct umct_softc *sc = usbd_xfer_softc(xfer); 583 struct usb_page_cache *pc; 584 int actlen; 585 586 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 587 588 switch (USB_GET_STATE(xfer)) { 589 case USB_ST_TRANSFERRED: 590 pc = usbd_xfer_get_frame(xfer, 0); 591 ucom_put_data(&sc->sc_ucom, pc, 0, actlen); 592 593 case USB_ST_SETUP: 594tr_setup: 595 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 596 usbd_transfer_submit(xfer); 597 return; 598 599 default: /* Error */ 600 if (error != USB_ERR_CANCELLED) { 601 /* try to clear stall first */ 602 usbd_xfer_set_stall(xfer); 603 goto tr_setup; 604 } 605 return; 606 } 607}
|