1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright 2019 Joyent, Inc. 28 */ 29 30 /* 31 * USB Serial CDC ACM driver 32 * 33 * 1. General Concepts 34 * ------------------- 35 * 36 * 1.1 Overview 37 * ------------ 38 * This driver supports devices that comply with the USB Communication 39 * Device Class Abstract Control Model (USB CDC ACM) specification, 40 * which is available at http://www.usb.org. Given the broad nature 41 * of communication equipment, this driver supports the following 42 * types of devices: 43 * + Telecommunications devices: analog modems, mobile phones; 44 * + Networking devices: cable modems; 45 * Except the above mentioned acm devices, this driver also supports 46 * some devices which provide modem-like function and have pairs of 47 * bulk in/out pipes. 48 * 49 * There are three classes that make up the definition for communication 50 * devices: the Communication Device Class, the Communication Interface 51 * Class and the Data Interface Class. The Communication Device Class 52 * is a device level definition and is used by the host to properly 53 * identify a communication device that may present several different 54 * types of interfaces. The Communication Interface Class defines a 55 * general-purpose mechanism that can be used to enable all types of 56 * communication services on the Universal Serial Bus (USB). The Data 57 * Interface Class defines a general-purpose mechanism to enable bulk 58 * transfer on the USB when the data does not meet the requirements 59 * for any other class. 60 * 61 * 1.2 Interface Definitions 62 * ------------------------- 63 * Communication Class Interface is used for device management and, 64 * optionally, call management. Device management includes the requests 65 * that manage the operational state of a device, the device responses, 66 * and event notifications. In Abstract Control Model, the device can 67 * provide an internal implementation of call management over the Data 68 * Class interface or the Communication Class interface. 69 * 70 * The Data Class defines a data interface as an interface with a class 71 * type of Data Class. Data transmission on a communication device is 72 * not restricted to interfaces using the Data Class. Rather, a data 73 * interface is used to transmit and/or receive data that is not 74 * defined by any other class. The data could be: 75 * + Some form of raw data from a communication line. 76 * + Legacy modem data. 77 * + Data using a proprietary format. 78 * 79 * 1.3 Endpoint Requirements 80 * ------------------------- 81 * The Communication Class interface requires one endpoint, the management 82 * element. Optionally, it can have an additional endpoint, the notification 83 * element. The management element uses the default endpoint for all 84 * standard and Communication Class-specific requests. The notification 85 * element normally uses an interrupt endpoint. 86 * 87 * The type of endpoints belonging to a Data Class interface are restricted 88 * to bulk, and are expected to exist in pairs of the same type (one In and 89 * one Out). 90 * 91 * 1.4 ACM Function Characteristics 92 * -------------------------------- 93 * With Abstract Control Model, the USB device understands standard 94 * V.25ter (AT) commands. The device contains a Datapump and micro- 95 * controller that handles the AT commands and relay controls. The 96 * device uses both a Data Class interface and a Communication Class. 97 * interface. 98 * 99 * A Communication Class interface of type Abstract Control Model will 100 * consist of a minimum of two pipes; one is used to implement the 101 * management element and the other to implement a notification element. 102 * In addition, the device can use two pipes to implement channels over 103 * which to carry unspecified data, typically over a Data Class interface. 104 * 105 * 1.5 ACM Serial Emulation 106 * ------------------------ 107 * The Abstract Control Model can bridge the gap between legacy modem 108 * devices and USB devices. To support certain types of legacy applications, 109 * two problems need to be addressed. The first is supporting specific 110 * legacy control signals and state variables which are addressed 111 * directly by the various carrier modulation standards. To support these 112 * requirement, additional requests and notifications have been created. 113 * Please refer to macro, beginning with USB_CDC_REQ_* and 114 * USB_CDC_NOTIFICATION_*. 115 * 116 * The second significant item which is needed to bridge the gap between 117 * legacy modem designs and the Abstract Control Model is a means to 118 * multiplex call control (AT commands) on the Data Class interface. 119 * Legacy modem designs are limited by only supporting one channel for 120 * both "AT" commands and the actual data. To allow this type of 121 * functionality, the device must have a means to specify this limitation 122 * to the host. 123 * 124 * When describing this type of device, the Communication Class interface 125 * would still specify a Abstract Control Model, but call control would 126 * actually occur over the Data Class interface. To describe this 127 * particular characteristic, the Call Management Functional Descriptor 128 * would have bit D1 of bmCapabilities set. 129 * 130 * 1.6 Other Bulk In/Out Devices 131 * ----------------------------- 132 * Some devices don't conform to USB CDC specification, but they provide 133 * modem-like function and have pairs of bulk in/out pipes. This driver 134 * supports this kind of device and exports term nodes by their pipes. 135 * 136 * 2. Implementation 137 * ----------------- 138 * 139 * 2.1 Overview 140 * ------------ 141 * It is a device-specific driver (DSD) working with USB generic serial 142 * driver (GSD). It implements the USB-to-serial device-specific driver 143 * interface (DSDI) which is offered by GSD. The interface is defined 144 * by ds_ops_t structure. 145 * 146 * 2.2 Port States 147 * --------------- 148 * For USB CDC ACM devices, this driver is attached to its interface, 149 * and exports one port for each interface. For other modem-like devices, 150 * this driver can dynamically find the ports in the current device, 151 * and export one port for each pair bulk in/out pipes. Each port can 152 * be operated independently. 153 * 154 * port_state: 155 * 156 * attach_ports 157 * | 158 * | 159 * | 160 * v 161 * USBSACM_PORT_CLOSED 162 * | ^ 163 * | | 164 * V | 165 * open_port close_port 166 * | ^ 167 * | | 168 * V | 169 * USBSACM_PORT_OPEN 170 * 171 * 172 * 2.3 Pipe States 173 * --------------- 174 * Each port has its own bulk in/out pipes and some ports could also have 175 * its own interrupt pipes (traced by usbsacm_port structure), which are 176 * opened during attach. The pipe status is as following: 177 * 178 * pipe_state: 179 * 180 * usbsacm_init_alloc_ports usbsacm_free_ports 181 * | ^ 182 * v | 183 * |---->------ USBSACM_PORT_CLOSED ------>------+ 184 * ^ | 185 * | reconnect/resume/open_port 186 * | | 187 * disconnect/suspend/close_port | 188 * | v 189 * +------<------ USBSACM_PIPE_IDLE ------<------| 190 * | | 191 * V ^ 192 * | | 193 * +-----------------+ +-----------+ 194 * | | 195 * V ^ 196 * | | 197 * rx_start/tx_start----->------failed------->---------| 198 * | | 199 * | bulkin_cb/bulkout_cb 200 * V | 201 * | ^ 202 * | | 203 * +----->----- USBSACM_PIPE_BUSY ---->------+ 204 * 205 * 206 * To get its status in a timely way, acm driver can get the status 207 * of the device by polling the interrupt pipe. 208 * 209 */ 210 211 #include <sys/types.h> 212 #include <sys/param.h> 213 #include <sys/conf.h> 214 #include <sys/stream.h> 215 #include <sys/strsun.h> 216 #include <sys/termio.h> 217 #include <sys/termiox.h> 218 #include <sys/ddi.h> 219 #include <sys/sunddi.h> 220 #include <sys/byteorder.h> 221 #define USBDRV_MAJOR_VER 2 222 #define USBDRV_MINOR_VER 0 223 #include <sys/usb/usba.h> 224 #include <sys/usb/usbdevs.h> 225 #include <sys/usb/usba/usba_types.h> 226 #include <sys/usb/clients/usbser/usbser.h> 227 #include <sys/usb/clients/usbser/usbser_dsdi.h> 228 #include <sys/usb/clients/usbcdc/usb_cdc.h> 229 #include <sys/usb/clients/usbser/usbsacm/usbsacm.h> 230 231 /* devops entry points */ 232 static int usbsacm_attach(dev_info_t *, ddi_attach_cmd_t); 233 static int usbsacm_detach(dev_info_t *, ddi_detach_cmd_t); 234 static int usbsacm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, 235 void **); 236 static int usbsacm_open(queue_t *, dev_t *, int, int, cred_t *); 237 238 /* DSD operations */ 239 static int usbsacm_ds_attach(ds_attach_info_t *); 240 static void usbsacm_ds_detach(ds_hdl_t); 241 static int usbsacm_ds_register_cb(ds_hdl_t, uint_t, ds_cb_t *); 242 static void usbsacm_ds_unregister_cb(ds_hdl_t, uint_t); 243 static int usbsacm_ds_open_port(ds_hdl_t, uint_t); 244 static int usbsacm_ds_close_port(ds_hdl_t, uint_t); 245 246 /* standard UART operations */ 247 static int usbsacm_ds_set_port_params(ds_hdl_t, uint_t, 248 ds_port_params_t *); 249 static int usbsacm_ds_set_modem_ctl(ds_hdl_t, uint_t, int, int); 250 static int usbsacm_ds_get_modem_ctl(ds_hdl_t, uint_t, int, int *); 251 static int usbsacm_ds_break_ctl(ds_hdl_t, uint_t, int); 252 253 /* data xfer */ 254 static int usbsacm_ds_tx(ds_hdl_t, uint_t, mblk_t *); 255 static mblk_t *usbsacm_ds_rx(ds_hdl_t, uint_t); 256 static void usbsacm_ds_stop(ds_hdl_t, uint_t, int); 257 static void usbsacm_ds_start(ds_hdl_t, uint_t, int); 258 259 /* fifo operations */ 260 static int usbsacm_ds_fifo_flush(ds_hdl_t, uint_t, int); 261 static int usbsacm_ds_fifo_drain(ds_hdl_t, uint_t, int); 262 static int usbsacm_wait_tx_drain(usbsacm_port_t *, int); 263 static int usbsacm_fifo_flush_locked(usbsacm_state_t *, uint_t, int); 264 265 /* power management and CPR */ 266 static int usbsacm_ds_suspend(ds_hdl_t); 267 static int usbsacm_ds_resume(ds_hdl_t); 268 static int usbsacm_ds_disconnect(ds_hdl_t); 269 static int usbsacm_ds_reconnect(ds_hdl_t); 270 static int usbsacm_ds_usb_power(ds_hdl_t, int, int, int *); 271 static int usbsacm_create_pm_components(usbsacm_state_t *); 272 static void usbsacm_destroy_pm_components(usbsacm_state_t *); 273 static void usbsacm_pm_set_busy(usbsacm_state_t *); 274 static void usbsacm_pm_set_idle(usbsacm_state_t *); 275 static int usbsacm_pwrlvl0(usbsacm_state_t *); 276 static int usbsacm_pwrlvl1(usbsacm_state_t *); 277 static int usbsacm_pwrlvl2(usbsacm_state_t *); 278 static int usbsacm_pwrlvl3(usbsacm_state_t *); 279 280 /* event handling */ 281 /* pipe callbacks */ 282 static void usbsacm_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *); 283 static void usbsacm_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *); 284 285 /* interrupt pipe */ 286 static void usbsacm_pipe_start_polling(usbsacm_port_t *acmp); 287 static void usbsacm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req); 288 static void usbsacm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req); 289 static void usbsacm_parse_intr_data(usbsacm_port_t *acmp, mblk_t *data); 290 291 /* Utility functions */ 292 /* data transfer routines */ 293 static int usbsacm_rx_start(usbsacm_port_t *); 294 static void usbsacm_tx_start(usbsacm_port_t *); 295 static int usbsacm_send_data(usbsacm_port_t *, mblk_t *); 296 297 /* Initialize or release resources */ 298 static int usbsacm_init_alloc_ports(usbsacm_state_t *); 299 static void usbsacm_free_ports(usbsacm_state_t *); 300 static void usbsacm_cleanup(usbsacm_state_t *); 301 302 /* analysis functional descriptors */ 303 static int usbsacm_get_descriptors(usbsacm_state_t *); 304 305 /* hotplug */ 306 static int usbsacm_restore_device_state(usbsacm_state_t *); 307 static int usbsacm_restore_port_state(usbsacm_state_t *); 308 309 /* pipe operations */ 310 static int usbsacm_open_port_pipes(usbsacm_port_t *); 311 static void usbsacm_close_port_pipes(usbsacm_port_t *); 312 static void usbsacm_close_pipes(usbsacm_state_t *); 313 static void usbsacm_disconnect_pipes(usbsacm_state_t *); 314 static int usbsacm_reconnect_pipes(usbsacm_state_t *); 315 316 /* vendor-specific commands */ 317 static int usbsacm_req_write(usbsacm_port_t *, uchar_t, uint16_t, 318 mblk_t **); 319 static int usbsacm_set_line_coding(usbsacm_port_t *, 320 usb_cdc_line_coding_t *); 321 static void usbsacm_mctl2reg(int mask, int val, uint8_t *); 322 static int usbsacm_reg2mctl(uint8_t); 323 324 /* misc */ 325 static void usbsacm_put_tail(mblk_t **, mblk_t *); 326 static void usbsacm_put_head(mblk_t **, mblk_t *); 327 328 329 /* 330 * Standard STREAMS driver definitions 331 */ 332 struct module_info usbsacm_modinfo = { 333 0, /* module id */ 334 "usbsacm", /* module name */ 335 USBSER_MIN_PKTSZ, /* min pkt size */ 336 USBSER_MAX_PKTSZ, /* max pkt size */ 337 USBSER_HIWAT, /* hi watermark */ 338 USBSER_LOWAT /* low watermark */ 339 }; 340 341 static struct qinit usbsacm_rinit = { 342 NULL, 343 usbser_rsrv, 344 usbsacm_open, 345 usbser_close, 346 NULL, 347 &usbsacm_modinfo, 348 NULL 349 }; 350 351 static struct qinit usbsacm_winit = { 352 usbser_wput, 353 usbser_wsrv, 354 NULL, 355 NULL, 356 NULL, 357 &usbsacm_modinfo, 358 NULL 359 }; 360 361 362 struct streamtab usbsacm_str_info = { 363 &usbsacm_rinit, &usbsacm_winit, NULL, NULL 364 }; 365 366 /* cb_ops structure */ 367 static struct cb_ops usbsacm_cb_ops = { 368 nodev, /* cb_open */ 369 nodev, /* cb_close */ 370 nodev, /* cb_strategy */ 371 nodev, /* cb_print */ 372 nodev, /* cb_dump */ 373 nodev, /* cb_read */ 374 nodev, /* cb_write */ 375 nodev, /* cb_ioctl */ 376 nodev, /* cb_devmap */ 377 nodev, /* cb_mmap */ 378 nodev, /* cb_segmap */ 379 nochpoll, /* cb_chpoll */ 380 ddi_prop_op, /* cb_prop_op */ 381 &usbsacm_str_info, /* cb_stream */ 382 (int)(D_64BIT | D_NEW | D_MP | D_HOTPLUG) /* cb_flag */ 383 }; 384 385 /* dev_ops structure */ 386 struct dev_ops usbsacm_ops = { 387 DEVO_REV, /* devo_rev */ 388 0, /* devo_refcnt */ 389 usbsacm_getinfo, /* devo_getinfo */ 390 nulldev, /* devo_identify */ 391 nulldev, /* devo_probe */ 392 usbsacm_attach, /* devo_attach */ 393 usbsacm_detach, /* devo_detach */ 394 nodev, /* devo_reset */ 395 &usbsacm_cb_ops, /* devo_cb_ops */ 396 (struct bus_ops *)NULL, /* devo_bus_ops */ 397 usbser_power, /* devo_power */ 398 ddi_quiesce_not_needed, /* devo_quiesce */ 399 }; 400 401 extern struct mod_ops mod_driverops; 402 /* modldrv structure */ 403 static struct modldrv modldrv = { 404 &mod_driverops, /* type of module - driver */ 405 "USB Serial CDC ACM driver", 406 &usbsacm_ops, 407 }; 408 409 /* modlinkage structure */ 410 static struct modlinkage modlinkage = { 411 MODREV_1, 412 &modldrv, 413 NULL 414 }; 415 416 static void *usbsacm_statep; /* soft state */ 417 418 /* 419 * DSD definitions 420 */ 421 static ds_ops_t usbsacm_ds_ops = { 422 DS_OPS_VERSION, 423 usbsacm_ds_attach, 424 usbsacm_ds_detach, 425 usbsacm_ds_register_cb, 426 usbsacm_ds_unregister_cb, 427 usbsacm_ds_open_port, 428 usbsacm_ds_close_port, 429 usbsacm_ds_usb_power, 430 usbsacm_ds_suspend, 431 usbsacm_ds_resume, 432 usbsacm_ds_disconnect, 433 usbsacm_ds_reconnect, 434 usbsacm_ds_set_port_params, 435 usbsacm_ds_set_modem_ctl, 436 usbsacm_ds_get_modem_ctl, 437 usbsacm_ds_break_ctl, 438 NULL, /* NULL if h/w doesn't support loopback */ 439 usbsacm_ds_tx, 440 usbsacm_ds_rx, 441 usbsacm_ds_stop, 442 usbsacm_ds_start, 443 usbsacm_ds_fifo_flush, 444 usbsacm_ds_fifo_drain 445 }; 446 447 /* 448 * baud code -> baud rate (0 means unsupported rate) 449 */ 450 static int usbsacm_speedtab[] = { 451 0, /* B0 */ 452 50, /* B50 */ 453 75, /* B75 */ 454 110, /* B110 */ 455 134, /* B134 */ 456 150, /* B150 */ 457 200, /* B200 */ 458 300, /* B300 */ 459 600, /* B600 */ 460 1200, /* B1200 */ 461 1800, /* B1800 */ 462 2400, /* B2400 */ 463 4800, /* B4800 */ 464 9600, /* B9600 */ 465 19200, /* B19200 */ 466 38400, /* B38400 */ 467 57600, /* B57600 */ 468 76800, /* B76800 */ 469 115200, /* B115200 */ 470 153600, /* B153600 */ 471 230400, /* B230400 */ 472 307200, /* B307200 */ 473 460800, /* B460800 */ 474 921600, /* B921600 */ 475 1000000, /* B1000000 */ 476 1152000, /* B1152000 */ 477 1500000, /* B1500000 */ 478 2000000, /* B2000000 */ 479 2500000, /* B2500000 */ 480 3000000, /* B3000000 */ 481 3500000, /* B3500000 */ 482 4000000, /* B4000000 */ 483 }; 484 485 486 static uint_t usbsacm_errlevel = USB_LOG_L4; 487 static uint_t usbsacm_errmask = 0xffffffff; 488 static uint_t usbsacm_instance_debug = (uint_t)-1; 489 490 491 /* 492 * usbsacm driver's entry points 493 * ----------------------------- 494 */ 495 /* 496 * Module-wide initialization routine. 497 */ 498 int 499 _init(void) 500 { 501 int error; 502 503 if ((error = mod_install(&modlinkage)) == 0) { 504 505 error = ddi_soft_state_init(&usbsacm_statep, 506 usbser_soft_state_size(), 1); 507 } 508 509 return (error); 510 } 511 512 513 /* 514 * Module-wide tear-down routine. 515 */ 516 int 517 _fini(void) 518 { 519 int error; 520 521 if ((error = mod_remove(&modlinkage)) == 0) { 522 ddi_soft_state_fini(&usbsacm_statep); 523 } 524 525 return (error); 526 } 527 528 529 int 530 _info(struct modinfo *modinfop) 531 { 532 return (mod_info(&modlinkage, modinfop)); 533 } 534 535 536 /* 537 * Device configuration entry points 538 */ 539 static int 540 usbsacm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 541 { 542 return (usbser_attach(dip, cmd, usbsacm_statep, &usbsacm_ds_ops)); 543 } 544 545 546 static int 547 usbsacm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 548 { 549 return (usbser_detach(dip, cmd, usbsacm_statep)); 550 } 551 552 553 int 554 usbsacm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 555 void **result) 556 { 557 return (usbser_getinfo(dip, infocmd, arg, result, usbsacm_statep)); 558 } 559 560 561 static int 562 usbsacm_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 563 { 564 return (usbser_open(rq, dev, flag, sflag, cr, usbsacm_statep)); 565 } 566 567 /* 568 * usbsacm_ds_detach: 569 * attach device instance, called from GSD attach 570 * initialize state and device, including: 571 * state variables, locks, device node 572 * device registration with system 573 * power management 574 */ 575 static int 576 usbsacm_ds_attach(ds_attach_info_t *aip) 577 { 578 usbsacm_state_t *acmp; 579 580 acmp = (usbsacm_state_t *)kmem_zalloc(sizeof (usbsacm_state_t), 581 KM_SLEEP); 582 acmp->acm_dip = aip->ai_dip; 583 acmp->acm_usb_events = aip->ai_usb_events; 584 acmp->acm_ports = NULL; 585 *aip->ai_hdl = (ds_hdl_t)acmp; 586 587 /* registers usbsacm with the USBA framework */ 588 if (usb_client_attach(acmp->acm_dip, USBDRV_VERSION, 589 0) != USB_SUCCESS) { 590 591 goto fail; 592 } 593 594 /* Get the configuration information of device */ 595 if (usb_get_dev_data(acmp->acm_dip, &acmp->acm_dev_data, 596 USB_PARSE_LVL_CFG, 0) != USB_SUCCESS) { 597 598 goto fail; 599 } 600 acmp->acm_def_ph = acmp->acm_dev_data->dev_default_ph; 601 acmp->acm_dev_state = USB_DEV_ONLINE; 602 mutex_init(&acmp->acm_mutex, NULL, MUTEX_DRIVER, 603 acmp->acm_dev_data->dev_iblock_cookie); 604 605 acmp->acm_lh = usb_alloc_log_hdl(acmp->acm_dip, "usbsacm", 606 &usbsacm_errlevel, &usbsacm_errmask, &usbsacm_instance_debug, 0); 607 608 /* Create power management components */ 609 if (usbsacm_create_pm_components(acmp) != USB_SUCCESS) { 610 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 611 "usbsacm_ds_attach: create pm components failed."); 612 613 goto fail; 614 } 615 616 /* Register to get callbacks for USB events */ 617 if (usb_register_event_cbs(acmp->acm_dip, acmp->acm_usb_events, 0) 618 != USB_SUCCESS) { 619 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 620 "usbsacm_ds_attach: register event callback failed."); 621 622 goto fail; 623 } 624 625 /* 626 * If devices conform to acm spec, driver will attach using class id; 627 * if not, using device id. 628 */ 629 if ((strcmp(DEVI(acmp->acm_dip)->devi_binding_name, 630 "usbif,class2.2") == 0) || 631 ((strcmp(DEVI(acmp->acm_dip)->devi_binding_name, 632 "usb,class2.2.0") == 0))) { 633 634 acmp->acm_compatibility = B_TRUE; 635 } else { 636 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 637 "usbsacm_ds_attach: A nonstandard device is attaching to " 638 "usbsacm driver. This device doesn't conform to " 639 "usb cdc spec."); 640 641 acmp->acm_compatibility = B_FALSE; 642 } 643 644 /* initialize state variables */ 645 if (usbsacm_init_alloc_ports(acmp) != USB_SUCCESS) { 646 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 647 "usbsacm_ds_attach: initialize port structure failed."); 648 649 goto fail; 650 } 651 *aip->ai_port_cnt = acmp->acm_port_cnt; 652 653 /* Get max data size of bulk transfer */ 654 if (usb_pipe_get_max_bulk_transfer_size(acmp->acm_dip, 655 &acmp->acm_xfer_sz) != USB_SUCCESS) { 656 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 657 "usbsacm_ds_attach: get max size of transfer failed."); 658 659 goto fail; 660 } 661 662 return (USB_SUCCESS); 663 fail: 664 usbsacm_cleanup(acmp); 665 666 return (USB_FAILURE); 667 } 668 669 670 /* 671 * usbsacm_ds_detach: 672 * detach device instance, called from GSD detach 673 */ 674 static void 675 usbsacm_ds_detach(ds_hdl_t hdl) 676 { 677 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 678 679 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 680 "usbsacm_ds_detach:"); 681 682 usbsacm_close_pipes(acmp); 683 usbsacm_cleanup(acmp); 684 } 685 686 687 /* 688 * usbsacm_ds_register_cb: 689 * GSD routine call ds_register_cb to register interrupt callbacks 690 * for the given port 691 */ 692 /*ARGSUSED*/ 693 static int 694 usbsacm_ds_register_cb(ds_hdl_t hdl, uint_t port_num, ds_cb_t *cb) 695 { 696 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 697 usbsacm_port_t *acm_port; 698 699 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 700 "usbsacm_ds_register_cb: acmp = 0x%p port_num = %d", 701 (void *)acmp, port_num); 702 703 /* Check if port number is greater than actual port number. */ 704 if (port_num >= acmp->acm_port_cnt) { 705 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 706 "usbsacm_ds_register_cb: port number is wrong."); 707 708 return (USB_FAILURE); 709 } 710 acm_port = &acmp->acm_ports[port_num]; 711 acm_port->acm_cb = *cb; 712 713 return (USB_SUCCESS); 714 } 715 716 717 /* 718 * usbsacm_ds_unregister_cb: 719 * GSD routine call ds_unregister_cb to unregister 720 * interrupt callbacks for the given port 721 */ 722 /*ARGSUSED*/ 723 static void 724 usbsacm_ds_unregister_cb(ds_hdl_t hdl, uint_t port_num) 725 { 726 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 727 usbsacm_port_t *acm_port; 728 729 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 730 "usbsacm_ds_unregister_cb: "); 731 732 if (port_num < acmp->acm_port_cnt) { 733 /* Release callback function */ 734 acm_port = &acmp->acm_ports[port_num]; 735 bzero(&acm_port->acm_cb, sizeof (acm_port->acm_cb)); 736 } 737 } 738 739 740 /* 741 * usbsacm_ds_open_port: 742 * GSD routine call ds_open_port 743 * to open the given port 744 */ 745 /*ARGSUSED*/ 746 static int 747 usbsacm_ds_open_port(ds_hdl_t hdl, uint_t port_num) 748 { 749 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 750 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 751 752 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 753 "usbsacm_ds_open_port: port_num = %d", port_num); 754 755 mutex_enter(&acm_port->acm_port_mutex); 756 /* Check the status of the given port and device */ 757 if ((acmp->acm_dev_state == USB_DEV_DISCONNECTED) || 758 (acm_port->acm_port_state != USBSACM_PORT_CLOSED)) { 759 mutex_exit(&acm_port->acm_port_mutex); 760 761 return (USB_FAILURE); 762 } 763 mutex_exit(&acm_port->acm_port_mutex); 764 765 usbsacm_pm_set_busy(acmp); 766 767 /* open pipes of port */ 768 if (usbsacm_open_port_pipes(acm_port) != USB_SUCCESS) { 769 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 770 "usbsacm_ds_open_port: open pipes failed."); 771 772 return (USB_FAILURE); 773 } 774 775 mutex_enter(&acm_port->acm_port_mutex); 776 /* data receipt */ 777 if (usbsacm_rx_start(acm_port) != USB_SUCCESS) { 778 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 779 "usbsacm_ds_open_port: start receive data failed."); 780 mutex_exit(&acm_port->acm_port_mutex); 781 782 return (USB_FAILURE); 783 } 784 acm_port->acm_port_state = USBSACM_PORT_OPEN; 785 786 mutex_exit(&acm_port->acm_port_mutex); 787 788 return (USB_SUCCESS); 789 } 790 791 792 /* 793 * usbsacm_ds_close_port: 794 * GSD routine call ds_close_port 795 * to close the given port 796 */ 797 /*ARGSUSED*/ 798 static int 799 usbsacm_ds_close_port(ds_hdl_t hdl, uint_t port_num) 800 { 801 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 802 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 803 int rval = USB_SUCCESS; 804 805 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 806 "usbsacm_ds_close_port: acmp = 0x%p", (void *)acmp); 807 808 mutex_enter(&acm_port->acm_port_mutex); 809 acm_port->acm_port_state = USBSACM_PORT_CLOSED; 810 mutex_exit(&acm_port->acm_port_mutex); 811 812 usbsacm_close_port_pipes(acm_port); 813 814 mutex_enter(&acm_port->acm_port_mutex); 815 rval = usbsacm_fifo_flush_locked(acmp, port_num, DS_TX | DS_RX); 816 mutex_exit(&acm_port->acm_port_mutex); 817 818 usbsacm_pm_set_idle(acmp); 819 820 return (rval); 821 } 822 823 824 /* 825 * usbsacm_ds_usb_power: 826 * GSD routine call ds_usb_power 827 * to set power level of the component 828 */ 829 /*ARGSUSED*/ 830 static int 831 usbsacm_ds_usb_power(ds_hdl_t hdl, int comp, int level, int *new_state) 832 { 833 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 834 usbsacm_pm_t *pm = acmp->acm_pm; 835 int rval = USB_SUCCESS; 836 837 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 838 "usbsacm_ds_usb_power: "); 839 840 /* check if pm is NULL */ 841 if (pm == NULL) { 842 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 843 "usbsacm_ds_usb_power: pm is NULL."); 844 845 return (USB_FAILURE); 846 } 847 848 mutex_enter(&acmp->acm_mutex); 849 /* 850 * check if we are transitioning to a legal power level 851 */ 852 if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) { 853 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 854 "usbsacm_ds_usb_power: " 855 "illegal power level %d, pwr_states=%x", 856 level, pm->pm_pwr_states); 857 mutex_exit(&acmp->acm_mutex); 858 859 return (USB_FAILURE); 860 } 861 862 /* 863 * if we are about to raise power and asked to lower power, fail 864 */ 865 if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) { 866 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 867 "usbsacm_ds_usb_power: wrong condition."); 868 mutex_exit(&acmp->acm_mutex); 869 870 return (USB_FAILURE); 871 } 872 873 /* 874 * Set the power status of device by request level. 875 */ 876 switch (level) { 877 case USB_DEV_OS_PWR_OFF: 878 rval = usbsacm_pwrlvl0(acmp); 879 880 break; 881 case USB_DEV_OS_PWR_1: 882 rval = usbsacm_pwrlvl1(acmp); 883 884 break; 885 case USB_DEV_OS_PWR_2: 886 rval = usbsacm_pwrlvl2(acmp); 887 888 break; 889 case USB_DEV_OS_FULL_PWR: 890 rval = usbsacm_pwrlvl3(acmp); 891 /* 892 * If usbser dev_state is DISCONNECTED or SUSPENDED, it shows 893 * that the usb serial device is disconnected/suspended while it 894 * is under power down state, now the device is powered up 895 * before it is reconnected/resumed. xxx_pwrlvl3() will set dev 896 * state to ONLINE, we need to set the dev state back to 897 * DISCONNECTED/SUSPENDED. 898 */ 899 if ((rval == USB_SUCCESS) && 900 ((*new_state == USB_DEV_DISCONNECTED) || 901 (*new_state == USB_DEV_SUSPENDED))) { 902 acmp->acm_dev_state = *new_state; 903 } 904 905 break; 906 } 907 908 *new_state = acmp->acm_dev_state; 909 mutex_exit(&acmp->acm_mutex); 910 911 return (rval); 912 } 913 914 915 /* 916 * usbsacm_ds_suspend: 917 * GSD routine call ds_suspend 918 * during CPR suspend 919 */ 920 static int 921 usbsacm_ds_suspend(ds_hdl_t hdl) 922 { 923 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 924 int state = USB_DEV_SUSPENDED; 925 926 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 927 "usbsacm_ds_suspend: "); 928 /* 929 * If the device is suspended while it is under PWRED_DOWN state, we 930 * need to keep the PWRED_DOWN state so that it could be powered up 931 * later. In the mean while, usbser dev state will be changed to 932 * SUSPENDED state. 933 */ 934 mutex_enter(&acmp->acm_mutex); 935 if (acmp->acm_dev_state != USB_DEV_PWRED_DOWN) { 936 /* set device status to suspend */ 937 acmp->acm_dev_state = USB_DEV_SUSPENDED; 938 } 939 mutex_exit(&acmp->acm_mutex); 940 941 usbsacm_disconnect_pipes(acmp); 942 943 return (state); 944 } 945 946 /* 947 * usbsacm_ds_resume: 948 * GSD routine call ds_resume 949 * during CPR resume 950 */ 951 /*ARGSUSED*/ 952 static int 953 usbsacm_ds_resume(ds_hdl_t hdl) 954 { 955 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 956 int current_state; 957 int ret; 958 959 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 960 "usbsacm_ds_resume: "); 961 962 mutex_enter(&acmp->acm_mutex); 963 current_state = acmp->acm_dev_state; 964 mutex_exit(&acmp->acm_mutex); 965 966 /* restore the status of device */ 967 if (current_state != USB_DEV_ONLINE) { 968 ret = usbsacm_restore_device_state(acmp); 969 } else { 970 ret = USB_DEV_ONLINE; 971 } 972 973 return (ret); 974 } 975 976 /* 977 * usbsacm_ds_disconnect: 978 * GSD routine call ds_disconnect 979 * to disconnect USB device 980 */ 981 static int 982 usbsacm_ds_disconnect(ds_hdl_t hdl) 983 { 984 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 985 int state = USB_DEV_DISCONNECTED; 986 987 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 988 "usbsacm_ds_disconnect: "); 989 990 /* 991 * If the device is disconnected while it is under PWRED_DOWN state, we 992 * need to keep the PWRED_DOWN state so that it could be powered up 993 * later. In the mean while, usbser dev state will be changed to 994 * DISCONNECTED state. 995 */ 996 mutex_enter(&acmp->acm_mutex); 997 if (acmp->acm_dev_state != USB_DEV_PWRED_DOWN) { 998 /* set device status to disconnected */ 999 acmp->acm_dev_state = USB_DEV_DISCONNECTED; 1000 } 1001 mutex_exit(&acmp->acm_mutex); 1002 1003 usbsacm_disconnect_pipes(acmp); 1004 1005 return (state); 1006 } 1007 1008 1009 /* 1010 * usbsacm_ds_reconnect: 1011 * GSD routine call ds_reconnect 1012 * to reconnect USB device 1013 */ 1014 /*ARGSUSED*/ 1015 static int 1016 usbsacm_ds_reconnect(ds_hdl_t hdl) 1017 { 1018 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1019 1020 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 1021 "usbsacm_ds_reconnect: "); 1022 1023 return (usbsacm_restore_device_state(acmp)); 1024 } 1025 1026 1027 /* 1028 * usbsacm_ds_set_port_params: 1029 * GSD routine call ds_set_port_params 1030 * to set one or more port parameters 1031 */ 1032 /*ARGSUSED*/ 1033 static int 1034 usbsacm_ds_set_port_params(ds_hdl_t hdl, uint_t port_num, ds_port_params_t *tp) 1035 { 1036 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1037 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1038 int i; 1039 uint_t ui; 1040 ds_port_param_entry_t *pe; 1041 usb_cdc_line_coding_t lc; 1042 int ret; 1043 1044 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1045 "usbsacm_ds_set_port_params: acmp = 0x%p", (void *)acmp); 1046 1047 mutex_enter(&acm_port->acm_port_mutex); 1048 /* 1049 * If device conform to acm spec, check if it support to set port param. 1050 */ 1051 if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 && 1052 acmp->acm_compatibility == B_TRUE) { 1053 1054 mutex_exit(&acm_port->acm_port_mutex); 1055 USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh, 1056 "usbsacm_ds_set_port_params: " 1057 "don't support Set_Line_Coding."); 1058 1059 return (USB_FAILURE); 1060 } 1061 1062 lc = acm_port->acm_line_coding; 1063 mutex_exit(&acm_port->acm_port_mutex); 1064 pe = tp->tp_entries; 1065 /* Get parameter information from ds_port_params_t */ 1066 for (i = 0; i < tp->tp_cnt; i++, pe++) { 1067 switch (pe->param) { 1068 case DS_PARAM_BAUD: 1069 /* Data terminal rate, in bits per second. */ 1070 ui = pe->val.ui; 1071 1072 /* if we don't support this speed, return USB_FAILURE */ 1073 if ((ui >= NELEM(usbsacm_speedtab)) || 1074 ((ui > 0) && (usbsacm_speedtab[ui] == 0))) { 1075 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 1076 "usbsacm_ds_set_port_params: " 1077 " error baud rate"); 1078 1079 return (USB_FAILURE); 1080 } 1081 lc.dwDTERate = LE_32(usbsacm_speedtab[ui]); 1082 1083 break; 1084 case DS_PARAM_PARITY: 1085 /* Parity Type */ 1086 if (pe->val.ui & PARENB) { 1087 if (pe->val.ui & PARODD) { 1088 lc.bParityType = USB_CDC_PARITY_ODD; 1089 } else { 1090 lc.bParityType = USB_CDC_PARITY_EVEN; 1091 } 1092 } else { 1093 lc.bParityType = USB_CDC_PARITY_NO; 1094 } 1095 1096 break; 1097 case DS_PARAM_STOPB: 1098 /* Stop bit */ 1099 if (pe->val.ui & CSTOPB) { 1100 lc.bCharFormat = USB_CDC_STOP_BITS_2; 1101 } else { 1102 lc.bCharFormat = USB_CDC_STOP_BITS_1; 1103 } 1104 1105 break; 1106 case DS_PARAM_CHARSZ: 1107 /* Data Bits */ 1108 switch (pe->val.ui) { 1109 case CS5: 1110 lc.bDataBits = 5; 1111 break; 1112 case CS6: 1113 lc.bDataBits = 6; 1114 break; 1115 case CS7: 1116 lc.bDataBits = 7; 1117 break; 1118 case CS8: 1119 default: 1120 lc.bDataBits = 8; 1121 break; 1122 } 1123 1124 break; 1125 default: 1126 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 1127 "usbsacm_ds_set_port_params: " 1128 "parameter 0x%x isn't supported", 1129 pe->param); 1130 1131 break; 1132 } 1133 } 1134 1135 if ((ret = usbsacm_set_line_coding(acm_port, &lc)) == USB_SUCCESS) { 1136 mutex_enter(&acm_port->acm_port_mutex); 1137 acm_port->acm_line_coding = lc; 1138 mutex_exit(&acm_port->acm_port_mutex); 1139 } 1140 1141 /* 1142 * If device don't conform to acm spec, return success directly. 1143 */ 1144 if (acmp->acm_compatibility != B_TRUE) { 1145 ret = USB_SUCCESS; 1146 } 1147 1148 return (ret); 1149 } 1150 1151 1152 /* 1153 * usbsacm_ds_set_modem_ctl: 1154 * GSD routine call ds_set_modem_ctl 1155 * to set modem control of the given port 1156 */ 1157 /*ARGSUSED*/ 1158 static int 1159 usbsacm_ds_set_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int val) 1160 { 1161 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1162 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1163 uint8_t new_mctl; 1164 int ret; 1165 1166 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1167 "usbsacm_ds_set_modem_ctl: mask = 0x%x val = 0x%x", 1168 mask, val); 1169 1170 mutex_enter(&acm_port->acm_port_mutex); 1171 /* 1172 * If device conform to acm spec, check if it support to set modem 1173 * controls. 1174 */ 1175 if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SERIAL_LINE) == 0 && 1176 acmp->acm_compatibility == B_TRUE) { 1177 1178 mutex_exit(&acm_port->acm_port_mutex); 1179 USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh, 1180 "usbsacm_ds_set_modem_ctl: " 1181 "don't support Set_Control_Line_State."); 1182 1183 return (USB_FAILURE); 1184 } 1185 1186 new_mctl = acm_port->acm_mctlout; 1187 mutex_exit(&acm_port->acm_port_mutex); 1188 1189 usbsacm_mctl2reg(mask, val, &new_mctl); 1190 1191 if ((acmp->acm_compatibility == B_FALSE) || ((ret = 1192 usbsacm_req_write(acm_port, USB_CDC_REQ_SET_CONTROL_LINE_STATE, 1193 new_mctl, NULL)) == USB_SUCCESS)) { 1194 mutex_enter(&acm_port->acm_port_mutex); 1195 acm_port->acm_mctlout = new_mctl; 1196 mutex_exit(&acm_port->acm_port_mutex); 1197 } 1198 1199 /* 1200 * If device don't conform to acm spec, return success directly. 1201 */ 1202 if (acmp->acm_compatibility != B_TRUE) { 1203 ret = USB_SUCCESS; 1204 } 1205 1206 return (ret); 1207 } 1208 1209 1210 /* 1211 * usbsacm_ds_get_modem_ctl: 1212 * GSD routine call ds_get_modem_ctl 1213 * to get modem control/status of the given port 1214 */ 1215 /*ARGSUSED*/ 1216 static int 1217 usbsacm_ds_get_modem_ctl(ds_hdl_t hdl, uint_t port_num, int mask, int *valp) 1218 { 1219 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1220 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1221 1222 mutex_enter(&acm_port->acm_port_mutex); 1223 *valp = usbsacm_reg2mctl(acm_port->acm_mctlout) & mask; 1224 /* 1225 * If device conform to acm spec, polling function can modify the value 1226 * of acm_mctlin; else set to default value. 1227 */ 1228 if (acmp->acm_compatibility) { 1229 *valp |= usbsacm_reg2mctl(acm_port->acm_mctlin) & mask; 1230 *valp |= (mask & (TIOCM_CD | TIOCM_CTS)); 1231 } else { 1232 *valp |= (mask & (TIOCM_CD | TIOCM_CTS | TIOCM_DSR | TIOCM_RI)); 1233 } 1234 mutex_exit(&acm_port->acm_port_mutex); 1235 1236 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1237 "usbsacm_ds_get_modem_ctl: val = 0x%x", *valp); 1238 1239 return (USB_SUCCESS); 1240 } 1241 1242 1243 /* 1244 * usbsacm_ds_tx: 1245 * GSD routine call ds_break_ctl 1246 * to set/clear break 1247 */ 1248 /*ARGSUSED*/ 1249 static int 1250 usbsacm_ds_break_ctl(ds_hdl_t hdl, uint_t port_num, int ctl) 1251 { 1252 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1253 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1254 1255 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1256 "usbsacm_ds_break_ctl: "); 1257 1258 mutex_enter(&acm_port->acm_port_mutex); 1259 /* 1260 * If device conform to acm spec, check if it support to send break. 1261 */ 1262 if ((acm_port->acm_cap & USB_CDC_ACM_CAP_SEND_BREAK) == 0 && 1263 acmp->acm_compatibility == B_TRUE) { 1264 1265 mutex_exit(&acm_port->acm_port_mutex); 1266 USB_DPRINTF_L2(PRINT_MASK_ALL, acmp->acm_lh, 1267 "usbsacm_ds_break_ctl: don't support send break."); 1268 1269 return (USB_FAILURE); 1270 } 1271 mutex_exit(&acm_port->acm_port_mutex); 1272 1273 return (usbsacm_req_write(acm_port, USB_CDC_REQ_SEND_BREAK, 1274 ((ctl == DS_ON) ? 0xffff : 0), NULL)); 1275 } 1276 1277 1278 /* 1279 * usbsacm_ds_tx: 1280 * GSD routine call ds_tx 1281 * to data transmit 1282 */ 1283 /*ARGSUSED*/ 1284 static int 1285 usbsacm_ds_tx(ds_hdl_t hdl, uint_t port_num, mblk_t *mp) 1286 { 1287 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1288 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1289 1290 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1291 "usbsacm_ds_tx: mp = 0x%p acmp = 0x%p", (void *)mp, (void *)acmp); 1292 1293 /* sanity checks */ 1294 if (mp == NULL) { 1295 1296 return (USB_SUCCESS); 1297 } 1298 if (MBLKL(mp) < 1) { 1299 freemsg(mp); 1300 1301 return (USB_SUCCESS); 1302 } 1303 1304 mutex_enter(&acm_port->acm_port_mutex); 1305 /* put mblk to tail of mblk chain */ 1306 usbsacm_put_tail(&acm_port->acm_tx_mp, mp); 1307 usbsacm_tx_start(acm_port); 1308 mutex_exit(&acm_port->acm_port_mutex); 1309 1310 return (USB_SUCCESS); 1311 } 1312 1313 1314 /* 1315 * usbsacm_ds_rx: 1316 * GSD routine call ds_rx; 1317 * to data receipt 1318 */ 1319 /*ARGSUSED*/ 1320 static mblk_t * 1321 usbsacm_ds_rx(ds_hdl_t hdl, uint_t port_num) 1322 { 1323 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1324 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1325 mblk_t *mp; 1326 1327 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1328 "usbsacm_ds_rx: acmp = 0x%p", (void *)acmp); 1329 1330 mutex_enter(&acm_port->acm_port_mutex); 1331 1332 mp = acm_port->acm_rx_mp; 1333 acm_port->acm_rx_mp = NULL; 1334 mutex_exit(&acm_port->acm_port_mutex); 1335 1336 return (mp); 1337 } 1338 1339 1340 /* 1341 * usbsacm_ds_stop: 1342 * GSD routine call ds_stop; 1343 * but acm spec don't define this function 1344 */ 1345 /*ARGSUSED*/ 1346 static void 1347 usbsacm_ds_stop(ds_hdl_t hdl, uint_t port_num, int dir) 1348 { 1349 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1350 1351 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 1352 "usbsacm_ds_stop: don't support!"); 1353 } 1354 1355 1356 /* 1357 * usbsacm_ds_start: 1358 * GSD routine call ds_start; 1359 * but acm spec don't define this function 1360 */ 1361 /*ARGSUSED*/ 1362 static void 1363 usbsacm_ds_start(ds_hdl_t hdl, uint_t port_num, int dir) 1364 { 1365 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1366 1367 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 1368 "usbsacm_ds_start: don't support!"); 1369 } 1370 1371 1372 /* 1373 * usbsacm_ds_fifo_flush: 1374 * GSD routine call ds_fifo_flush 1375 * to flush FIFOs 1376 */ 1377 /*ARGSUSED*/ 1378 static int 1379 usbsacm_ds_fifo_flush(ds_hdl_t hdl, uint_t port_num, int dir) 1380 { 1381 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1382 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1383 int ret = USB_SUCCESS; 1384 1385 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1386 "usbsacm_ds_fifo_flush: "); 1387 1388 mutex_enter(&acm_port->acm_port_mutex); 1389 ret = usbsacm_fifo_flush_locked(acmp, port_num, dir); 1390 mutex_exit(&acm_port->acm_port_mutex); 1391 1392 return (ret); 1393 } 1394 1395 1396 /* 1397 * usbsacm_ds_fifo_drain: 1398 * GSD routine call ds_fifo_drain 1399 * to wait until empty output FIFO 1400 */ 1401 /*ARGSUSED*/ 1402 static int 1403 usbsacm_ds_fifo_drain(ds_hdl_t hdl, uint_t port_num, int timeout) 1404 { 1405 usbsacm_state_t *acmp = (usbsacm_state_t *)hdl; 1406 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1407 int rval = USB_SUCCESS; 1408 1409 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 1410 "usbsacm_ds_fifo_drain: "); 1411 1412 mutex_enter(&acm_port->acm_port_mutex); 1413 ASSERT(acm_port->acm_port_state == USBSACM_PORT_OPEN); 1414 1415 if (usbsacm_wait_tx_drain(acm_port, timeout) != USB_SUCCESS) { 1416 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 1417 "usbsacm_ds_fifo_drain: fifo drain failed."); 1418 mutex_exit(&acm_port->acm_port_mutex); 1419 1420 return (USB_FAILURE); 1421 } 1422 1423 mutex_exit(&acm_port->acm_port_mutex); 1424 1425 return (rval); 1426 } 1427 1428 1429 /* 1430 * usbsacm_fifo_flush_locked: 1431 * flush FIFOs of the given ports 1432 */ 1433 /*ARGSUSED*/ 1434 static int 1435 usbsacm_fifo_flush_locked(usbsacm_state_t *acmp, uint_t port_num, int dir) 1436 { 1437 usbsacm_port_t *acm_port = &acmp->acm_ports[port_num]; 1438 1439 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 1440 "usbsacm_fifo_flush_locked: "); 1441 1442 /* flush transmit FIFO if DS_TX is set */ 1443 if ((dir & DS_TX) && acm_port->acm_tx_mp) { 1444 freemsg(acm_port->acm_tx_mp); 1445 acm_port->acm_tx_mp = NULL; 1446 } 1447 /* flush received FIFO if DS_RX is set */ 1448 if ((dir & DS_RX) && acm_port->acm_rx_mp) { 1449 freemsg(acm_port->acm_rx_mp); 1450 acm_port->acm_rx_mp = NULL; 1451 } 1452 1453 return (USB_SUCCESS); 1454 } 1455 1456 1457 /* 1458 * usbsacm_get_bulk_pipe_number: 1459 * Calculate the number of bulk in or out pipes in current device. 1460 */ 1461 static int 1462 usbsacm_get_bulk_pipe_number(usbsacm_state_t *acmp, uint_t dir) 1463 { 1464 int count = 0; 1465 int i, skip; 1466 usb_if_data_t *cur_if; 1467 int ep_num; 1468 int if_num; 1469 1470 USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh, 1471 "usbsacm_get_bulk_pipe_number: "); 1472 1473 cur_if = acmp->acm_dev_data->dev_curr_cfg->cfg_if; 1474 if_num = acmp->acm_dev_data->dev_curr_cfg->cfg_n_if; 1475 1476 /* search each interface which have bulk endpoint */ 1477 for (i = 0; i < if_num; i++) { 1478 ep_num = cur_if->if_alt->altif_n_ep; 1479 1480 /* 1481 * search endpoints in current interface, 1482 * which type is input parameter 'dir' 1483 */ 1484 for (skip = 0; skip < ep_num; skip++) { 1485 if (usb_lookup_ep_data(acmp->acm_dip, 1486 acmp->acm_dev_data, i, 0, skip, 1487 USB_EP_ATTR_BULK, dir) == NULL) { 1488 1489 /* 1490 * If not found, skip the internal loop 1491 * and search the next interface. 1492 */ 1493 break; 1494 } 1495 count++; 1496 } 1497 1498 cur_if++; 1499 } 1500 1501 return (count); 1502 } 1503 1504 1505 /* 1506 * port management 1507 * --------------- 1508 * initialize, release port. 1509 * 1510 * 1511 * usbsacm_init_ports_status: 1512 * Initialize the port status for the current device. 1513 */ 1514 static int 1515 usbsacm_init_ports_status(usbsacm_state_t *acmp) 1516 { 1517 usbsacm_port_t *cur_port; 1518 int i, skip; 1519 int if_num; 1520 int intr_if_no = 0; 1521 int ep_num; 1522 usb_if_data_t *cur_if; 1523 1524 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 1525 "usbsacm_init_ports_status: acmp = 0x%p", (void *)acmp); 1526 1527 /* Initialize the port status to default value */ 1528 for (i = 0; i < acmp->acm_port_cnt; i++) { 1529 cur_port = &acmp->acm_ports[i]; 1530 1531 cv_init(&cur_port->acm_tx_cv, NULL, CV_DRIVER, NULL); 1532 1533 cur_port->acm_port_state = USBSACM_PORT_CLOSED; 1534 1535 cur_port->acm_line_coding.dwDTERate = LE_32((uint32_t)9600); 1536 cur_port->acm_line_coding.bCharFormat = 0; 1537 cur_port->acm_line_coding.bParityType = USB_CDC_PARITY_NO; 1538 cur_port->acm_line_coding.bDataBits = 8; 1539 cur_port->acm_device = acmp; 1540 mutex_init(&cur_port->acm_port_mutex, NULL, MUTEX_DRIVER, 1541 acmp->acm_dev_data->dev_iblock_cookie); 1542 } 1543 1544 /* 1545 * If device conform to cdc acm spec, parse function descriptors. 1546 */ 1547 if (acmp->acm_compatibility == B_TRUE) { 1548 1549 if (usbsacm_get_descriptors(acmp) != USB_SUCCESS) { 1550 1551 return (USB_FAILURE); 1552 } 1553 1554 return (USB_SUCCESS); 1555 } 1556 1557 /* 1558 * If device don't conform to spec, search pairs of bulk in/out 1559 * endpoints and fill port structure. 1560 */ 1561 cur_if = acmp->acm_dev_data->dev_curr_cfg->cfg_if; 1562 if_num = acmp->acm_dev_data->dev_curr_cfg->cfg_n_if; 1563 cur_port = acmp->acm_ports; 1564 1565 /* search each interface which have bulk in and out */ 1566 for (i = 0; i < if_num; i++) { 1567 ep_num = cur_if->if_alt->altif_n_ep; 1568 1569 for (skip = 0; skip < ep_num; skip++) { 1570 1571 /* search interrupt pipe. */ 1572 if ((usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1573 i, 0, skip, USB_EP_ATTR_INTR, USB_EP_DIR_IN) != NULL)) { 1574 1575 intr_if_no = i; 1576 } 1577 1578 /* search pair of bulk in/out endpoints. */ 1579 if ((usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1580 i, 0, skip, USB_EP_ATTR_BULK, USB_EP_DIR_IN) == NULL) || 1581 (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1582 i, 0, skip, USB_EP_ATTR_BULK, USB_EP_DIR_OUT) == NULL)) { 1583 1584 continue; 1585 } 1586 1587 cur_port->acm_data_if_no = i; 1588 cur_port->acm_ctrl_if_no = intr_if_no; 1589 cur_port->acm_data_port_no = skip; 1590 cur_port++; 1591 intr_if_no = 0; 1592 } 1593 1594 cur_if++; 1595 } 1596 1597 return (USB_SUCCESS); 1598 } 1599 1600 1601 /* 1602 * usbsacm_init_alloc_ports: 1603 * Allocate memory and initialize the port state for the current device. 1604 */ 1605 static int 1606 usbsacm_init_alloc_ports(usbsacm_state_t *acmp) 1607 { 1608 int rval = USB_SUCCESS; 1609 int count_in = 0, count_out = 0; 1610 1611 if (acmp->acm_compatibility) { 1612 acmp->acm_port_cnt = 1; 1613 } else { 1614 /* Calculate the number of the bulk in/out endpoints */ 1615 count_in = usbsacm_get_bulk_pipe_number(acmp, USB_EP_DIR_IN); 1616 count_out = usbsacm_get_bulk_pipe_number(acmp, USB_EP_DIR_OUT); 1617 1618 USB_DPRINTF_L3(PRINT_MASK_OPEN, acmp->acm_lh, 1619 "usbsacm_init_alloc_ports: count_in = %d, count_out = %d", 1620 count_in, count_out); 1621 1622 acmp->acm_port_cnt = min(count_in, count_out); 1623 } 1624 1625 /* return if not found any pair of bulk in/out endpoint. */ 1626 if (acmp->acm_port_cnt == 0) { 1627 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 1628 "usbsacm_init_alloc_ports: port count is zero."); 1629 1630 return (USB_FAILURE); 1631 } 1632 1633 /* allocate memory for ports */ 1634 acmp->acm_ports = (usbsacm_port_t *)kmem_zalloc(acmp->acm_port_cnt * 1635 sizeof (usbsacm_port_t), KM_SLEEP); 1636 if (acmp->acm_ports == NULL) { 1637 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 1638 "usbsacm_init_alloc_ports: allocate memory failed."); 1639 1640 return (USB_FAILURE); 1641 } 1642 1643 /* fill the status of port structure. */ 1644 rval = usbsacm_init_ports_status(acmp); 1645 if (rval != USB_SUCCESS) { 1646 usbsacm_free_ports(acmp); 1647 } 1648 1649 return (rval); 1650 } 1651 1652 1653 /* 1654 * usbsacm_free_ports: 1655 * Release ports and deallocate memory. 1656 */ 1657 static void 1658 usbsacm_free_ports(usbsacm_state_t *acmp) 1659 { 1660 int i; 1661 1662 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 1663 "usbsacm_free_ports: "); 1664 1665 /* Release memory and data structure for each port */ 1666 for (i = 0; i < acmp->acm_port_cnt; i++) { 1667 cv_destroy(&acmp->acm_ports[i].acm_tx_cv); 1668 mutex_destroy(&acmp->acm_ports[i].acm_port_mutex); 1669 } 1670 kmem_free((caddr_t)acmp->acm_ports, sizeof (usbsacm_port_t) * 1671 acmp->acm_port_cnt); 1672 acmp->acm_ports = NULL; 1673 } 1674 1675 1676 /* 1677 * usbsacm_get_descriptors: 1678 * analysis functional descriptors of acm device 1679 */ 1680 static int 1681 usbsacm_get_descriptors(usbsacm_state_t *acmp) 1682 { 1683 int i; 1684 usb_cfg_data_t *cfg; 1685 usb_alt_if_data_t *altif; 1686 usb_cvs_data_t *cvs; 1687 int mgmt_cap = 0; 1688 int master_if = -1, slave_if = -1; 1689 usbsacm_port_t *acm_port = acmp->acm_ports; 1690 usb_dev_descr_t *dd; 1691 1692 USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh, 1693 "usbsacm_get_descriptors: "); 1694 1695 dd = acmp->acm_dev_data->dev_descr; 1696 cfg = acmp->acm_dev_data->dev_curr_cfg; 1697 /* set default control and data interface */ 1698 acm_port->acm_ctrl_if_no = acm_port->acm_data_if_no = 0; 1699 1700 /* get current interfaces */ 1701 acm_port->acm_ctrl_if_no = acmp->acm_dev_data->dev_curr_if; 1702 if (cfg->cfg_if[acm_port->acm_ctrl_if_no].if_n_alt == 0) { 1703 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1704 "usbsacm_get_descriptors: elements in if_alt is %d", 1705 cfg->cfg_if[acm_port->acm_ctrl_if_no].if_n_alt); 1706 1707 return (USB_FAILURE); 1708 } 1709 1710 altif = &cfg->cfg_if[acm_port->acm_ctrl_if_no].if_alt[0]; 1711 1712 /* 1713 * Based on CDC specification, ACM devices usually include the 1714 * following function descriptors: Header, ACM, Union and Call 1715 * Management function descriptors. This loop search tree data 1716 * structure for each acm class descriptor. 1717 */ 1718 for (i = 0; i < altif->altif_n_cvs; i++) { 1719 1720 cvs = &altif->altif_cvs[i]; 1721 1722 if ((cvs->cvs_buf == NULL) || 1723 (cvs->cvs_buf[1] != USB_CDC_CS_INTERFACE)) { 1724 continue; 1725 } 1726 1727 switch (cvs->cvs_buf[2]) { 1728 case USB_CDC_DESCR_TYPE_CALL_MANAGEMENT: 1729 /* parse call management functional descriptor. */ 1730 if (cvs->cvs_buf_len >= 5) { 1731 mgmt_cap = cvs->cvs_buf[3]; 1732 acm_port->acm_data_if_no = cvs->cvs_buf[4]; 1733 } 1734 break; 1735 case USB_CDC_DESCR_TYPE_ACM: 1736 /* parse ACM functional descriptor. */ 1737 if (cvs->cvs_buf_len >= 4) { 1738 acm_port->acm_cap = cvs->cvs_buf[3]; 1739 } 1740 1741 /* 1742 * The Sigma Designs, Inc. USB device does not report 1743 * itself as implementing the full ACM spec. However, 1744 * it does function as a usb serial modem, so we opt to 1745 * scribble in the reported functionality if we 1746 * determine the USB device matches this vendor 1747 * and product ID. 1748 */ 1749 if (dd->idVendor == USB_VENDOR_SIGMADESIGNS && 1750 dd->idProduct == USB_PRODUCT_SIGMADESIGNS_ZW090) { 1751 acm_port->acm_cap |= 1752 USB_CDC_ACM_CAP_SERIAL_LINE; 1753 } 1754 break; 1755 case USB_CDC_DESCR_TYPE_UNION: 1756 /* parse Union functional descriptor. */ 1757 if (cvs->cvs_buf_len >= 5) { 1758 master_if = cvs->cvs_buf[3]; 1759 slave_if = cvs->cvs_buf[4]; 1760 } 1761 break; 1762 default: 1763 break; 1764 } 1765 } 1766 1767 /* For usb acm devices, it must satisfy the following options. */ 1768 if (cfg->cfg_n_if < 2) { 1769 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1770 "usbsacm_get_descriptors: # of interfaces %d < 2", 1771 cfg->cfg_n_if); 1772 1773 return (USB_FAILURE); 1774 } 1775 1776 if (acm_port->acm_data_if_no == 0 && 1777 slave_if != acm_port->acm_data_if_no) { 1778 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1779 "usbsacm_get_descriptors: Device hasn't call management " 1780 "descriptor and use Union Descriptor."); 1781 1782 acm_port->acm_data_if_no = slave_if; 1783 } 1784 1785 if ((master_if != acm_port->acm_ctrl_if_no) || 1786 (slave_if != acm_port->acm_data_if_no)) { 1787 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1788 "usbsacm_get_descriptors: control interface or " 1789 "data interface don't match."); 1790 1791 return (USB_FAILURE); 1792 } 1793 1794 /* 1795 * We usually need both call and data capabilities, but 1796 * some devices, such as Nokia mobile phones, don't provide 1797 * call management descriptor, so we just give a warning 1798 * message. 1799 */ 1800 if (((mgmt_cap & USB_CDC_CALL_MGMT_CAP_CALL_MGMT) == 0) || 1801 ((mgmt_cap & USB_CDC_CALL_MGMT_CAP_DATA_INTERFACE) == 0)) { 1802 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1803 "usbsacm_get_descriptors: " 1804 "insufficient mgmt capabilities %x", 1805 mgmt_cap); 1806 } 1807 1808 if ((acm_port->acm_ctrl_if_no >= cfg->cfg_n_if) || 1809 (acm_port->acm_data_if_no >= cfg->cfg_n_if)) { 1810 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1811 "usbsacm_get_descriptors: control interface %d or " 1812 "data interface %d out of range.", 1813 acm_port->acm_ctrl_if_no, acm_port->acm_data_if_no); 1814 1815 return (USB_FAILURE); 1816 } 1817 1818 /* control interface must have interrupt endpoint */ 1819 if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1820 acm_port->acm_ctrl_if_no, 0, 0, USB_EP_ATTR_INTR, 1821 USB_EP_DIR_IN) == NULL) { 1822 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1823 "usbsacm_get_descriptors: " 1824 "ctrl interface %d has no interrupt endpoint", 1825 acm_port->acm_data_if_no); 1826 1827 return (USB_FAILURE); 1828 } 1829 1830 /* data interface must have bulk in and out */ 1831 if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1832 acm_port->acm_data_if_no, 0, 0, USB_EP_ATTR_BULK, 1833 USB_EP_DIR_IN) == NULL) { 1834 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1835 "usbsacm_get_descriptors: " 1836 "data interface %d has no bulk in endpoint", 1837 acm_port->acm_data_if_no); 1838 1839 return (USB_FAILURE); 1840 } 1841 if (usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 1842 acm_port->acm_data_if_no, 0, 0, USB_EP_ATTR_BULK, 1843 USB_EP_DIR_OUT) == NULL) { 1844 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1845 "usbsacm_get_descriptors: " 1846 "data interface %d has no bulk out endpoint", 1847 acm_port->acm_data_if_no); 1848 1849 return (USB_FAILURE); 1850 } 1851 1852 return (USB_SUCCESS); 1853 } 1854 1855 1856 /* 1857 * usbsacm_cleanup: 1858 * Release resources of current device during detach. 1859 */ 1860 static void 1861 usbsacm_cleanup(usbsacm_state_t *acmp) 1862 { 1863 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 1864 "usbsacm_cleanup: "); 1865 1866 if (acmp != NULL) { 1867 /* free ports */ 1868 if (acmp->acm_ports != NULL) { 1869 usbsacm_free_ports(acmp); 1870 } 1871 1872 /* unregister callback function */ 1873 if (acmp->acm_usb_events != NULL) { 1874 usb_unregister_event_cbs(acmp->acm_dip, 1875 acmp->acm_usb_events); 1876 } 1877 1878 /* destroy power management components */ 1879 if (acmp->acm_pm != NULL) { 1880 usbsacm_destroy_pm_components(acmp); 1881 } 1882 1883 /* free description of device tree. */ 1884 if (acmp->acm_def_ph != NULL) { 1885 mutex_destroy(&acmp->acm_mutex); 1886 1887 usb_free_descr_tree(acmp->acm_dip, acmp->acm_dev_data); 1888 acmp->acm_def_ph = NULL; 1889 } 1890 1891 if (acmp->acm_lh != NULL) { 1892 usb_free_log_hdl(acmp->acm_lh); 1893 acmp->acm_lh = NULL; 1894 } 1895 1896 /* detach client device */ 1897 if (acmp->acm_dev_data != NULL) { 1898 usb_client_detach(acmp->acm_dip, acmp->acm_dev_data); 1899 } 1900 1901 kmem_free((caddr_t)acmp, sizeof (usbsacm_state_t)); 1902 } 1903 } 1904 1905 1906 /* 1907 * usbsacm_restore_device_state: 1908 * restore device state after CPR resume or reconnect 1909 */ 1910 static int 1911 usbsacm_restore_device_state(usbsacm_state_t *acmp) 1912 { 1913 int state; 1914 1915 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1916 "usbsacm_restore_device_state: "); 1917 1918 mutex_enter(&acmp->acm_mutex); 1919 state = acmp->acm_dev_state; 1920 mutex_exit(&acmp->acm_mutex); 1921 1922 /* Check device status */ 1923 if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) { 1924 1925 return (state); 1926 } 1927 1928 /* Check if we are talking to the same device */ 1929 if (usb_check_same_device(acmp->acm_dip, acmp->acm_lh, USB_LOG_L0, 1930 -1, USB_CHK_ALL, NULL) != USB_SUCCESS) { 1931 mutex_enter(&acmp->acm_mutex); 1932 state = acmp->acm_dev_state = USB_DEV_DISCONNECTED; 1933 mutex_exit(&acmp->acm_mutex); 1934 1935 return (state); 1936 } 1937 1938 if (state == USB_DEV_DISCONNECTED) { 1939 USB_DPRINTF_L1(PRINT_MASK_ALL, acmp->acm_lh, 1940 "usbsacm_restore_device_state: Device has been reconnected " 1941 "but data may have been lost"); 1942 } 1943 1944 /* reconnect pipes */ 1945 if (usbsacm_reconnect_pipes(acmp) != USB_SUCCESS) { 1946 1947 return (state); 1948 } 1949 1950 /* 1951 * init device state 1952 */ 1953 mutex_enter(&acmp->acm_mutex); 1954 state = acmp->acm_dev_state = USB_DEV_ONLINE; 1955 mutex_exit(&acmp->acm_mutex); 1956 1957 if ((usbsacm_restore_port_state(acmp) != USB_SUCCESS)) { 1958 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1959 "usbsacm_restore_device_state: failed"); 1960 } 1961 1962 return (state); 1963 } 1964 1965 1966 /* 1967 * usbsacm_restore_port_state: 1968 * restore ports state after CPR resume or reconnect 1969 */ 1970 static int 1971 usbsacm_restore_port_state(usbsacm_state_t *acmp) 1972 { 1973 int i, ret = USB_SUCCESS; 1974 usbsacm_port_t *cur_port; 1975 1976 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 1977 "usbsacm_restore_port_state: "); 1978 1979 /* restore status of all ports */ 1980 for (i = 0; i < acmp->acm_port_cnt; i++) { 1981 cur_port = &acmp->acm_ports[i]; 1982 mutex_enter(&cur_port->acm_port_mutex); 1983 if (cur_port->acm_port_state != USBSACM_PORT_OPEN) { 1984 mutex_exit(&cur_port->acm_port_mutex); 1985 1986 continue; 1987 } 1988 mutex_exit(&cur_port->acm_port_mutex); 1989 1990 if ((ret = usbsacm_set_line_coding(cur_port, 1991 &cur_port->acm_line_coding)) != USB_SUCCESS) { 1992 USB_DPRINTF_L2(PRINT_MASK_ATTA, acmp->acm_lh, 1993 "usbsacm_restore_port_state: failed."); 1994 } 1995 } 1996 1997 return (ret); 1998 } 1999 2000 2001 /* 2002 * pipe management 2003 * --------------- 2004 * 2005 * 2006 * usbsacm_open_port_pipes: 2007 * Open pipes of one port and set port structure; 2008 * Each port includes three pipes: bulk in, bulk out and interrupt. 2009 */ 2010 static int 2011 usbsacm_open_port_pipes(usbsacm_port_t *acm_port) 2012 { 2013 int rval = USB_SUCCESS; 2014 usbsacm_state_t *acmp = acm_port->acm_device; 2015 usb_ep_data_t *in_data, *out_data, *intr_pipe; 2016 usb_pipe_policy_t policy; 2017 2018 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 2019 "usbsacm_open_port_pipes: acmp = 0x%p", (void *)acmp); 2020 2021 /* Get bulk and interrupt endpoint data */ 2022 intr_pipe = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 2023 acm_port->acm_ctrl_if_no, 0, 0, 2024 USB_EP_ATTR_INTR, USB_EP_DIR_IN); 2025 in_data = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 2026 acm_port->acm_data_if_no, 0, acm_port->acm_data_port_no, 2027 USB_EP_ATTR_BULK, USB_EP_DIR_IN); 2028 out_data = usb_lookup_ep_data(acmp->acm_dip, acmp->acm_dev_data, 2029 acm_port->acm_data_if_no, 0, acm_port->acm_data_port_no, 2030 USB_EP_ATTR_BULK, USB_EP_DIR_OUT); 2031 2032 /* Bulk in and out must exist meanwhile. */ 2033 if ((in_data == NULL) || (out_data == NULL)) { 2034 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2035 "usbsacm_open_port_pipes: look up bulk pipe failed in " 2036 "interface %d port %d", 2037 acm_port->acm_data_if_no, acm_port->acm_data_port_no); 2038 2039 return (USB_FAILURE); 2040 } 2041 2042 /* 2043 * If device conform to acm spec, it must have an interrupt pipe 2044 * for this port. 2045 */ 2046 if (acmp->acm_compatibility == B_TRUE && intr_pipe == NULL) { 2047 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2048 "usbsacm_open_port_pipes: look up interrupt pipe failed in " 2049 "interface %d", acm_port->acm_ctrl_if_no); 2050 2051 return (USB_FAILURE); 2052 } 2053 2054 policy.pp_max_async_reqs = 2; 2055 2056 /* Open bulk in endpoint */ 2057 if (usb_pipe_open(acmp->acm_dip, &in_data->ep_descr, &policy, 2058 USB_FLAGS_SLEEP, &acm_port->acm_bulkin_ph) != USB_SUCCESS) { 2059 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2060 "usbsacm_open_port_pipes: open bulkin pipe failed!"); 2061 2062 return (USB_FAILURE); 2063 } 2064 2065 /* Open bulk out endpoint */ 2066 if (usb_pipe_open(acmp->acm_dip, &out_data->ep_descr, &policy, 2067 USB_FLAGS_SLEEP, &acm_port->acm_bulkout_ph) != USB_SUCCESS) { 2068 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2069 "usbsacm_open_port_pipes: open bulkout pipe failed!"); 2070 2071 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph, 2072 USB_FLAGS_SLEEP, NULL, NULL); 2073 2074 return (USB_FAILURE); 2075 } 2076 2077 /* Open interrupt endpoint if found. */ 2078 if (intr_pipe != NULL) { 2079 2080 if (usb_pipe_open(acmp->acm_dip, &intr_pipe->ep_descr, &policy, 2081 USB_FLAGS_SLEEP, &acm_port->acm_intr_ph) != USB_SUCCESS) { 2082 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2083 "usbsacm_open_port_pipes: " 2084 "open control pipe failed"); 2085 2086 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph, 2087 USB_FLAGS_SLEEP, NULL, NULL); 2088 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkout_ph, 2089 USB_FLAGS_SLEEP, NULL, NULL); 2090 2091 return (USB_FAILURE); 2092 } 2093 } 2094 2095 /* initialize the port structure. */ 2096 mutex_enter(&acm_port->acm_port_mutex); 2097 acm_port->acm_bulkin_size = in_data->ep_descr.wMaxPacketSize; 2098 acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE; 2099 acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE; 2100 if (acm_port->acm_intr_ph != NULL) { 2101 acm_port->acm_intr_state = USBSACM_PIPE_IDLE; 2102 acm_port->acm_intr_ep_descr = intr_pipe->ep_descr; 2103 } 2104 mutex_exit(&acm_port->acm_port_mutex); 2105 2106 if (acm_port->acm_intr_ph != NULL) { 2107 2108 usbsacm_pipe_start_polling(acm_port); 2109 } 2110 2111 return (rval); 2112 } 2113 2114 2115 /* 2116 * usbsacm_close_port_pipes: 2117 * Close pipes of one port and reset port structure to closed; 2118 * Each port includes three pipes: bulk in, bulk out and interrupt. 2119 */ 2120 static void 2121 usbsacm_close_port_pipes(usbsacm_port_t *acm_port) 2122 { 2123 usbsacm_state_t *acmp = acm_port->acm_device; 2124 2125 mutex_enter(&acm_port->acm_port_mutex); 2126 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 2127 "usbsacm_close_port_pipes: acm_bulkin_state = %d", 2128 acm_port->acm_bulkin_state); 2129 2130 /* 2131 * Check the status of the given port. If port is closing or closed, 2132 * return directly. 2133 */ 2134 if ((acm_port->acm_bulkin_state == USBSACM_PIPE_CLOSED) || 2135 (acm_port->acm_bulkin_state == USBSACM_PIPE_CLOSING)) { 2136 USB_DPRINTF_L2(PRINT_MASK_CLOSE, acmp->acm_lh, 2137 "usbsacm_close_port_pipes: port is closing or has closed"); 2138 mutex_exit(&acm_port->acm_port_mutex); 2139 2140 return; 2141 } 2142 2143 acm_port->acm_bulkin_state = USBSACM_PIPE_CLOSING; 2144 mutex_exit(&acm_port->acm_port_mutex); 2145 2146 /* Close pipes */ 2147 usb_pipe_reset(acmp->acm_dip, acm_port->acm_bulkin_ph, 2148 USB_FLAGS_SLEEP, 0, 0); 2149 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkin_ph, 2150 USB_FLAGS_SLEEP, 0, 0); 2151 usb_pipe_close(acmp->acm_dip, acm_port->acm_bulkout_ph, 2152 USB_FLAGS_SLEEP, 0, 0); 2153 if (acm_port->acm_intr_ph != NULL) { 2154 usb_pipe_stop_intr_polling(acm_port->acm_intr_ph, 2155 USB_FLAGS_SLEEP); 2156 usb_pipe_close(acmp->acm_dip, acm_port->acm_intr_ph, 2157 USB_FLAGS_SLEEP, 0, 0); 2158 } 2159 2160 mutex_enter(&acm_port->acm_port_mutex); 2161 /* Reset the status of pipes to closed */ 2162 acm_port->acm_bulkin_state = USBSACM_PIPE_CLOSED; 2163 acm_port->acm_bulkin_ph = NULL; 2164 acm_port->acm_bulkout_state = USBSACM_PIPE_CLOSED; 2165 acm_port->acm_bulkout_ph = NULL; 2166 if (acm_port->acm_intr_ph != NULL) { 2167 acm_port->acm_intr_state = USBSACM_PIPE_CLOSED; 2168 acm_port->acm_intr_ph = NULL; 2169 } 2170 2171 mutex_exit(&acm_port->acm_port_mutex); 2172 2173 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 2174 "usbsacm_close_port_pipes: port has been closed."); 2175 } 2176 2177 2178 /* 2179 * usbsacm_close_pipes: 2180 * close all opened pipes of current devices. 2181 */ 2182 static void 2183 usbsacm_close_pipes(usbsacm_state_t *acmp) 2184 { 2185 int i; 2186 2187 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 2188 "usbsacm_close_pipes: "); 2189 2190 /* Close all ports */ 2191 for (i = 0; i < acmp->acm_port_cnt; i++) { 2192 usbsacm_close_port_pipes(&acmp->acm_ports[i]); 2193 } 2194 } 2195 2196 2197 /* 2198 * usbsacm_disconnect_pipes: 2199 * this function just call usbsacm_close_pipes. 2200 */ 2201 static void 2202 usbsacm_disconnect_pipes(usbsacm_state_t *acmp) 2203 { 2204 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 2205 "usbsacm_disconnect_pipes: "); 2206 2207 usbsacm_close_pipes(acmp); 2208 } 2209 2210 2211 /* 2212 * usbsacm_reconnect_pipes: 2213 * reconnect pipes in CPR resume or reconnect 2214 */ 2215 static int 2216 usbsacm_reconnect_pipes(usbsacm_state_t *acmp) 2217 { 2218 usbsacm_port_t *cur_port = acmp->acm_ports; 2219 int i; 2220 2221 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 2222 "usbsacm_reconnect_pipes: "); 2223 2224 /* reopen all ports of current device. */ 2225 for (i = 0; i < acmp->acm_port_cnt; i++) { 2226 cur_port = &acmp->acm_ports[i]; 2227 2228 mutex_enter(&cur_port->acm_port_mutex); 2229 /* 2230 * If port status is open, reopen it; 2231 * else retain the current status. 2232 */ 2233 if (cur_port->acm_port_state == USBSACM_PORT_OPEN) { 2234 2235 mutex_exit(&cur_port->acm_port_mutex); 2236 if (usbsacm_open_port_pipes(cur_port) != USB_SUCCESS) { 2237 USB_DPRINTF_L4(PRINT_MASK_OPEN, acmp->acm_lh, 2238 "usbsacm_reconnect_pipes: " 2239 "open port %d failed.", i); 2240 2241 return (USB_FAILURE); 2242 } 2243 mutex_enter(&cur_port->acm_port_mutex); 2244 } 2245 mutex_exit(&cur_port->acm_port_mutex); 2246 } 2247 2248 return (USB_SUCCESS); 2249 } 2250 2251 /* 2252 * usbsacm_bulkin_cb: 2253 * Bulk In regular and exeception callback; 2254 * USBA framework will call this callback 2255 * after deal with bulkin request. 2256 */ 2257 /*ARGSUSED*/ 2258 static void 2259 usbsacm_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 2260 { 2261 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->bulk_client_private; 2262 usbsacm_state_t *acmp = acm_port->acm_device; 2263 mblk_t *data; 2264 int data_len; 2265 2266 data = req->bulk_data; 2267 data_len = (data) ? MBLKL(data) : 0; 2268 2269 mutex_enter(&acm_port->acm_port_mutex); 2270 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 2271 "usbsacm_bulkin_cb: " 2272 "acm_bulkin_state = %d acm_port_state = %d data_len = %d", 2273 acm_port->acm_bulkin_state, acm_port->acm_port_state, data_len); 2274 2275 if ((acm_port->acm_port_state == USBSACM_PORT_OPEN) && (data_len) && 2276 (req->bulk_completion_reason == USB_CR_OK)) { 2277 mutex_exit(&acm_port->acm_port_mutex); 2278 /* prevent USBA from freeing data along with the request */ 2279 req->bulk_data = NULL; 2280 2281 /* save data on the receive list */ 2282 usbsacm_put_tail(&acm_port->acm_rx_mp, data); 2283 2284 /* invoke GSD receive callback */ 2285 if (acm_port->acm_cb.cb_rx) { 2286 acm_port->acm_cb.cb_rx(acm_port->acm_cb.cb_arg); 2287 } 2288 mutex_enter(&acm_port->acm_port_mutex); 2289 } 2290 mutex_exit(&acm_port->acm_port_mutex); 2291 2292 usb_free_bulk_req(req); 2293 2294 /* receive more */ 2295 mutex_enter(&acm_port->acm_port_mutex); 2296 if (((acm_port->acm_bulkin_state == USBSACM_PIPE_BUSY) || 2297 (acm_port->acm_bulkin_state == USBSACM_PIPE_IDLE)) && 2298 (acm_port->acm_port_state == USBSACM_PORT_OPEN) && 2299 (acmp->acm_dev_state == USB_DEV_ONLINE)) { 2300 if (usbsacm_rx_start(acm_port) != USB_SUCCESS) { 2301 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2302 "usbsacm_bulkin_cb: restart rx fail " 2303 "acm_port_state = %d", acm_port->acm_port_state); 2304 } 2305 } else if (acm_port->acm_bulkin_state == USBSACM_PIPE_BUSY) { 2306 acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE; 2307 } 2308 mutex_exit(&acm_port->acm_port_mutex); 2309 } 2310 2311 2312 /* 2313 * usbsacm_bulkout_cb: 2314 * Bulk Out regular and exeception callback; 2315 * USBA framework will call this callback function 2316 * after deal with bulkout request. 2317 */ 2318 /*ARGSUSED*/ 2319 static void 2320 usbsacm_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req) 2321 { 2322 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->bulk_client_private; 2323 usbsacm_state_t *acmp = acm_port->acm_device; 2324 int data_len; 2325 mblk_t *data = req->bulk_data; 2326 2327 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 2328 "usbsacm_bulkout_cb: acmp = 0x%p", (void *)acmp); 2329 2330 data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0; 2331 2332 /* put untransferred residue back on the transfer list */ 2333 if (req->bulk_completion_reason && (data_len > 0)) { 2334 usbsacm_put_head(&acm_port->acm_tx_mp, data); 2335 req->bulk_data = NULL; 2336 } 2337 2338 usb_free_bulk_req(req); 2339 2340 /* invoke GSD transmit callback */ 2341 if (acm_port->acm_cb.cb_tx) { 2342 acm_port->acm_cb.cb_tx(acm_port->acm_cb.cb_arg); 2343 } 2344 2345 /* send more */ 2346 mutex_enter(&acm_port->acm_port_mutex); 2347 acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE; 2348 if (acm_port->acm_tx_mp == NULL) { 2349 cv_broadcast(&acm_port->acm_tx_cv); 2350 } else { 2351 usbsacm_tx_start(acm_port); 2352 } 2353 mutex_exit(&acm_port->acm_port_mutex); 2354 } 2355 2356 2357 /* 2358 * usbsacm_rx_start: 2359 * start data receipt 2360 */ 2361 static int 2362 usbsacm_rx_start(usbsacm_port_t *acm_port) 2363 { 2364 usbsacm_state_t *acmp = acm_port->acm_device; 2365 usb_bulk_req_t *br; 2366 int rval = USB_FAILURE; 2367 int data_len; 2368 2369 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 2370 "usbsacm_rx_start: acm_xfer_sz = 0x%lx acm_bulkin_size = 0x%lx", 2371 acmp->acm_xfer_sz, acm_port->acm_bulkin_size); 2372 2373 acm_port->acm_bulkin_state = USBSACM_PIPE_BUSY; 2374 /* 2375 * Qualcomm CDMA card won't response the first request, 2376 * if the following code don't multiply by 2. 2377 */ 2378 data_len = min(acmp->acm_xfer_sz, acm_port->acm_bulkin_size * 2); 2379 mutex_exit(&acm_port->acm_port_mutex); 2380 2381 br = usb_alloc_bulk_req(acmp->acm_dip, data_len, USB_FLAGS_SLEEP); 2382 if (br == NULL) { 2383 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2384 "usbsacm_rx_start: allocate bulk request failed"); 2385 2386 mutex_enter(&acm_port->acm_port_mutex); 2387 2388 return (USB_FAILURE); 2389 } 2390 /* initialize bulk in request. */ 2391 br->bulk_len = data_len; 2392 br->bulk_timeout = USBSACM_BULKIN_TIMEOUT; 2393 br->bulk_cb = usbsacm_bulkin_cb; 2394 br->bulk_exc_cb = usbsacm_bulkin_cb; 2395 br->bulk_client_private = (usb_opaque_t)acm_port; 2396 br->bulk_attributes = USB_ATTRS_AUTOCLEARING 2397 | USB_ATTRS_SHORT_XFER_OK; 2398 2399 rval = usb_pipe_bulk_xfer(acm_port->acm_bulkin_ph, br, 0); 2400 2401 mutex_enter(&acm_port->acm_port_mutex); 2402 if (rval != USB_SUCCESS) { 2403 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2404 "usbsacm_rx_start: bulk transfer failed %d", rval); 2405 usb_free_bulk_req(br); 2406 acm_port->acm_bulkin_state = USBSACM_PIPE_IDLE; 2407 } 2408 2409 return (rval); 2410 } 2411 2412 2413 /* 2414 * usbsacm_tx_start: 2415 * start data transmit 2416 */ 2417 static void 2418 usbsacm_tx_start(usbsacm_port_t *acm_port) 2419 { 2420 int len; /* bytes we can transmit */ 2421 mblk_t *data; /* data to be transmitted */ 2422 int data_len; /* bytes in 'data' */ 2423 mblk_t *mp; /* current msgblk */ 2424 int copylen; /* bytes copy from 'mp' to 'data' */ 2425 int rval; 2426 usbsacm_state_t *acmp = acm_port->acm_device; 2427 2428 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 2429 "usbsacm_tx_start: "); 2430 2431 /* check the transmitted data. */ 2432 if (acm_port->acm_tx_mp == NULL) { 2433 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2434 "usbsacm_tx_start: acm_tx_mp is NULL"); 2435 2436 return; 2437 } 2438 2439 /* check pipe status */ 2440 if (acm_port->acm_bulkout_state != USBSACM_PIPE_IDLE) { 2441 2442 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2443 "usbsacm_tx_start: error state in bulkout endpoint"); 2444 2445 return; 2446 } 2447 ASSERT(MBLKL(acm_port->acm_tx_mp) > 0); 2448 2449 /* send as much data as port can receive */ 2450 len = min(msgdsize(acm_port->acm_tx_mp), acmp->acm_xfer_sz); 2451 2452 if (len == 0) { 2453 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2454 "usbsacm_tx_start: data len is 0"); 2455 2456 return; 2457 } 2458 2459 /* allocate memory for sending data. */ 2460 if ((data = allocb(len, BPRI_LO)) == NULL) { 2461 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2462 "usbsacm_tx_start: failure in allocate memory"); 2463 2464 return; 2465 } 2466 2467 /* 2468 * copy no more than 'len' bytes from mblk chain to transmit mblk 'data' 2469 */ 2470 data_len = 0; 2471 while ((data_len < len) && acm_port->acm_tx_mp) { 2472 /* Get the first mblk from chain. */ 2473 mp = acm_port->acm_tx_mp; 2474 copylen = min(MBLKL(mp), len - data_len); 2475 bcopy(mp->b_rptr, data->b_wptr, copylen); 2476 mp->b_rptr += copylen; 2477 data->b_wptr += copylen; 2478 data_len += copylen; 2479 2480 if (MBLKL(mp) < 1) { 2481 acm_port->acm_tx_mp = unlinkb(mp); 2482 freeb(mp); 2483 } else { 2484 ASSERT(data_len == len); 2485 } 2486 } 2487 2488 if (data_len <= 0) { 2489 freeb(data); 2490 2491 return; 2492 } 2493 2494 acm_port->acm_bulkout_state = USBSACM_PIPE_BUSY; 2495 2496 mutex_exit(&acm_port->acm_port_mutex); 2497 /* send request. */ 2498 rval = usbsacm_send_data(acm_port, data); 2499 mutex_enter(&acm_port->acm_port_mutex); 2500 2501 /* 2502 * If send failed, retransmit data when acm_tx_mp is null. 2503 */ 2504 if (rval != USB_SUCCESS) { 2505 acm_port->acm_bulkout_state = USBSACM_PIPE_IDLE; 2506 if (acm_port->acm_tx_mp == NULL) { 2507 usbsacm_put_head(&acm_port->acm_tx_mp, data); 2508 } 2509 } 2510 } 2511 2512 2513 /* 2514 * usbsacm_send_data: 2515 * data transfer 2516 */ 2517 static int 2518 usbsacm_send_data(usbsacm_port_t *acm_port, mblk_t *data) 2519 { 2520 usbsacm_state_t *acmp = acm_port->acm_device; 2521 usb_bulk_req_t *br; 2522 int rval; 2523 int data_len = MBLKL(data); 2524 2525 USB_DPRINTF_L4(PRINT_MASK_EVENTS, acmp->acm_lh, 2526 "usbsacm_send_data: data address is 0x%p, length = %d", 2527 (void *)data, data_len); 2528 2529 br = usb_alloc_bulk_req(acmp->acm_dip, 0, USB_FLAGS_SLEEP); 2530 if (br == NULL) { 2531 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 2532 "usbsacm_send_data: alloc req failed."); 2533 2534 return (USB_FAILURE); 2535 } 2536 2537 /* initialize the bulk out request */ 2538 br->bulk_data = data; 2539 br->bulk_len = data_len; 2540 br->bulk_timeout = USBSACM_BULKOUT_TIMEOUT; 2541 br->bulk_cb = usbsacm_bulkout_cb; 2542 br->bulk_exc_cb = usbsacm_bulkout_cb; 2543 br->bulk_client_private = (usb_opaque_t)acm_port; 2544 br->bulk_attributes = USB_ATTRS_AUTOCLEARING; 2545 2546 rval = usb_pipe_bulk_xfer(acm_port->acm_bulkout_ph, br, 0); 2547 2548 if (rval != USB_SUCCESS) { 2549 USB_DPRINTF_L2(PRINT_MASK_EVENTS, acmp->acm_lh, 2550 "usbsacm_send_data: Send Data failed."); 2551 2552 /* 2553 * Don't free it in usb_free_bulk_req because it will 2554 * be linked in usbsacm_put_head 2555 */ 2556 br->bulk_data = NULL; 2557 2558 usb_free_bulk_req(br); 2559 } 2560 2561 return (rval); 2562 } 2563 2564 /* 2565 * usbsacm_wait_tx_drain: 2566 * wait until local tx buffer drains. 2567 * 'timeout' is in seconds, zero means wait forever 2568 */ 2569 static int 2570 usbsacm_wait_tx_drain(usbsacm_port_t *acm_port, int timeout) 2571 { 2572 clock_t until; 2573 int over = 0; 2574 2575 until = ddi_get_lbolt() + drv_usectohz(1000 * 1000 * timeout); 2576 2577 while (acm_port->acm_tx_mp && !over) { 2578 if (timeout > 0) { 2579 over = (cv_timedwait_sig(&acm_port->acm_tx_cv, 2580 &acm_port->acm_port_mutex, until) <= 0); 2581 } else { 2582 over = (cv_wait_sig(&acm_port->acm_tx_cv, 2583 &acm_port->acm_port_mutex) == 0); 2584 } 2585 } 2586 2587 return ((acm_port->acm_tx_mp == NULL) ? USB_SUCCESS : USB_FAILURE); 2588 } 2589 2590 2591 /* 2592 * usbsacm_req_write: 2593 * send command over control pipe 2594 */ 2595 static int 2596 usbsacm_req_write(usbsacm_port_t *acm_port, uchar_t request, uint16_t value, 2597 mblk_t **data) 2598 { 2599 usbsacm_state_t *acmp = acm_port->acm_device; 2600 usb_ctrl_setup_t setup; 2601 usb_cb_flags_t cb_flags; 2602 usb_cr_t cr; 2603 2604 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 2605 "usbsacm_req_write: "); 2606 2607 /* initialize the control request. */ 2608 setup.bmRequestType = USBSACM_REQ_WRITE_IF; 2609 setup.bRequest = request; 2610 setup.wValue = value; 2611 setup.wIndex = acm_port->acm_ctrl_if_no; 2612 setup.wLength = ((data != NULL) && (*data != NULL)) ? MBLKL(*data) : 0; 2613 setup.attrs = 0; 2614 2615 return (usb_pipe_ctrl_xfer_wait(acmp->acm_def_ph, &setup, data, 2616 &cr, &cb_flags, 0)); 2617 } 2618 2619 2620 /* 2621 * usbsacm_set_line_coding: 2622 * Send USB_CDC_REQ_SET_LINE_CODING request 2623 */ 2624 static int 2625 usbsacm_set_line_coding(usbsacm_port_t *acm_port, usb_cdc_line_coding_t *lc) 2626 { 2627 mblk_t *bp; 2628 int ret; 2629 2630 /* allocate mblk and copy supplied structure into it */ 2631 if ((bp = allocb(USB_CDC_LINE_CODING_LEN, BPRI_HI)) == NULL) { 2632 2633 return (USB_NO_RESOURCES); 2634 } 2635 2636 #ifndef __lock_lint /* warlock gets confused here */ 2637 /* LINTED E_BAD_PTR_CAST_ALIGN */ 2638 *((usb_cdc_line_coding_t *)bp->b_wptr) = *lc; 2639 bp->b_wptr += USB_CDC_LINE_CODING_LEN; 2640 #endif 2641 2642 ret = usbsacm_req_write(acm_port, USB_CDC_REQ_SET_LINE_CODING, 0, &bp); 2643 2644 if (bp != NULL) { 2645 freeb(bp); 2646 } 2647 2648 return (ret); 2649 } 2650 2651 2652 2653 /* 2654 * usbsacm_mctl2reg: 2655 * Set Modem control status 2656 */ 2657 static void 2658 usbsacm_mctl2reg(int mask, int val, uint8_t *line_ctl) 2659 { 2660 if (mask & TIOCM_RTS) { 2661 if (val & TIOCM_RTS) { 2662 *line_ctl |= USB_CDC_ACM_CONTROL_RTS; 2663 } else { 2664 *line_ctl &= ~USB_CDC_ACM_CONTROL_RTS; 2665 } 2666 } 2667 if (mask & TIOCM_DTR) { 2668 if (val & TIOCM_DTR) { 2669 *line_ctl |= USB_CDC_ACM_CONTROL_DTR; 2670 } else { 2671 *line_ctl &= ~USB_CDC_ACM_CONTROL_DTR; 2672 } 2673 } 2674 } 2675 2676 2677 /* 2678 * usbsacm_reg2mctl: 2679 * Get Modem control status 2680 */ 2681 static int 2682 usbsacm_reg2mctl(uint8_t line_ctl) 2683 { 2684 int val = 0; 2685 2686 if (line_ctl & USB_CDC_ACM_CONTROL_RTS) { 2687 val |= TIOCM_RTS; 2688 } 2689 if (line_ctl & USB_CDC_ACM_CONTROL_DTR) { 2690 val |= TIOCM_DTR; 2691 } 2692 if (line_ctl & USB_CDC_ACM_CONTROL_DSR) { 2693 val |= TIOCM_DSR; 2694 } 2695 if (line_ctl & USB_CDC_ACM_CONTROL_RNG) { 2696 val |= TIOCM_RI; 2697 } 2698 2699 return (val); 2700 } 2701 2702 2703 /* 2704 * misc routines 2705 * ------------- 2706 * 2707 */ 2708 2709 /* 2710 * usbsacm_put_tail: 2711 * link a message block to tail of message 2712 * account for the case when message is null 2713 */ 2714 static void 2715 usbsacm_put_tail(mblk_t **mpp, mblk_t *bp) 2716 { 2717 if (*mpp) { 2718 linkb(*mpp, bp); 2719 } else { 2720 *mpp = bp; 2721 } 2722 } 2723 2724 2725 /* 2726 * usbsacm_put_head: 2727 * put a message block at the head of the message 2728 * account for the case when message is null 2729 */ 2730 static void 2731 usbsacm_put_head(mblk_t **mpp, mblk_t *bp) 2732 { 2733 if (*mpp) { 2734 linkb(bp, *mpp); 2735 } 2736 *mpp = bp; 2737 } 2738 2739 2740 /* 2741 * power management 2742 * ---------------- 2743 * 2744 * usbsacm_create_pm_components: 2745 * create PM components 2746 */ 2747 static int 2748 usbsacm_create_pm_components(usbsacm_state_t *acmp) 2749 { 2750 dev_info_t *dip = acmp->acm_dip; 2751 usbsacm_pm_t *pm; 2752 uint_t pwr_states; 2753 usb_dev_descr_t *dev_descr; 2754 2755 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 2756 "usbsacm_create_pm_components: "); 2757 2758 if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) { 2759 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 2760 "usbsacm_create_pm_components: failed"); 2761 2762 return (USB_SUCCESS); 2763 } 2764 2765 pm = acmp->acm_pm = 2766 (usbsacm_pm_t *)kmem_zalloc(sizeof (usbsacm_pm_t), KM_SLEEP); 2767 2768 pm->pm_pwr_states = (uint8_t)pwr_states; 2769 pm->pm_cur_power = USB_DEV_OS_FULL_PWR; 2770 /* 2771 * Qualcomm CDMA card won't response the following control commands 2772 * after receive USB_REMOTE_WAKEUP_ENABLE. So we just set 2773 * pm_wakeup_enable to 0 for this specific device. 2774 */ 2775 dev_descr = acmp->acm_dev_data->dev_descr; 2776 if (dev_descr->idVendor == 0x5c6 && dev_descr->idProduct == 0x3100) { 2777 pm->pm_wakeup_enabled = 0; 2778 } else { 2779 pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip, 2780 USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS); 2781 } 2782 2783 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2784 2785 return (USB_SUCCESS); 2786 } 2787 2788 2789 /* 2790 * usbsacm_destroy_pm_components: 2791 * destroy PM components 2792 */ 2793 static void 2794 usbsacm_destroy_pm_components(usbsacm_state_t *acmp) 2795 { 2796 usbsacm_pm_t *pm = acmp->acm_pm; 2797 dev_info_t *dip = acmp->acm_dip; 2798 int rval; 2799 2800 USB_DPRINTF_L4(PRINT_MASK_CLOSE, acmp->acm_lh, 2801 "usbsacm_destroy_pm_components: "); 2802 2803 if (acmp->acm_dev_state != USB_DEV_DISCONNECTED) { 2804 if (pm->pm_wakeup_enabled) { 2805 rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2806 if (rval != DDI_SUCCESS) { 2807 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 2808 "usbsacm_destroy_pm_components: " 2809 "raising power failed (%d)", rval); 2810 } 2811 2812 rval = usb_handle_remote_wakeup(dip, 2813 USB_REMOTE_WAKEUP_DISABLE); 2814 if (rval != USB_SUCCESS) { 2815 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 2816 "usbsacm_destroy_pm_components: " 2817 "disable remote wakeup failed (%d)", rval); 2818 } 2819 } 2820 2821 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF); 2822 } 2823 kmem_free((caddr_t)pm, sizeof (usbsacm_pm_t)); 2824 acmp->acm_pm = NULL; 2825 } 2826 2827 2828 /* 2829 * usbsacm_pm_set_busy: 2830 * mark device busy and raise power 2831 */ 2832 static void 2833 usbsacm_pm_set_busy(usbsacm_state_t *acmp) 2834 { 2835 usbsacm_pm_t *pm = acmp->acm_pm; 2836 dev_info_t *dip = acmp->acm_dip; 2837 int rval; 2838 2839 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 2840 "usbsacm_pm_set_busy: pm = 0x%p", (void *)pm); 2841 2842 if (pm == NULL) { 2843 2844 return; 2845 } 2846 2847 mutex_enter(&acmp->acm_mutex); 2848 /* if already marked busy, just increment the counter */ 2849 if (pm->pm_busy_cnt++ > 0) { 2850 mutex_exit(&acmp->acm_mutex); 2851 2852 return; 2853 } 2854 2855 (void) pm_busy_component(dip, 0); 2856 2857 if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) { 2858 mutex_exit(&acmp->acm_mutex); 2859 2860 return; 2861 } 2862 2863 /* need to raise power */ 2864 pm->pm_raise_power = B_TRUE; 2865 mutex_exit(&acmp->acm_mutex); 2866 2867 rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR); 2868 if (rval != DDI_SUCCESS) { 2869 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 2870 "usbsacm_pm_set_busy: raising power failed"); 2871 } 2872 2873 mutex_enter(&acmp->acm_mutex); 2874 pm->pm_raise_power = B_FALSE; 2875 mutex_exit(&acmp->acm_mutex); 2876 } 2877 2878 2879 /* 2880 * usbsacm_pm_set_idle: 2881 * mark device idle 2882 */ 2883 static void 2884 usbsacm_pm_set_idle(usbsacm_state_t *acmp) 2885 { 2886 usbsacm_pm_t *pm = acmp->acm_pm; 2887 dev_info_t *dip = acmp->acm_dip; 2888 2889 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 2890 "usbsacm_pm_set_idle: "); 2891 2892 if (pm == NULL) { 2893 2894 return; 2895 } 2896 2897 /* 2898 * if more ports use the device, do not mark as yet 2899 */ 2900 mutex_enter(&acmp->acm_mutex); 2901 if (--pm->pm_busy_cnt > 0) { 2902 mutex_exit(&acmp->acm_mutex); 2903 2904 return; 2905 } 2906 2907 if (pm) { 2908 (void) pm_idle_component(dip, 0); 2909 } 2910 mutex_exit(&acmp->acm_mutex); 2911 } 2912 2913 2914 /* 2915 * usbsacm_pwrlvl0: 2916 * Functions to handle power transition for OS levels 0 -> 3 2917 * The same level as OS state, different from USB state 2918 */ 2919 static int 2920 usbsacm_pwrlvl0(usbsacm_state_t *acmp) 2921 { 2922 int rval; 2923 int i; 2924 usbsacm_port_t *cur_port = acmp->acm_ports; 2925 2926 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 2927 "usbsacm_pwrlvl0: "); 2928 2929 switch (acmp->acm_dev_state) { 2930 case USB_DEV_ONLINE: 2931 /* issue USB D3 command to the device */ 2932 rval = usb_set_device_pwrlvl3(acmp->acm_dip); 2933 ASSERT(rval == USB_SUCCESS); 2934 2935 if (cur_port != NULL) { 2936 for (i = 0; i < acmp->acm_port_cnt; i++) { 2937 cur_port = &acmp->acm_ports[i]; 2938 if (cur_port->acm_intr_ph != NULL && 2939 cur_port->acm_port_state != 2940 USBSACM_PORT_CLOSED) { 2941 2942 mutex_exit(&acmp->acm_mutex); 2943 usb_pipe_stop_intr_polling( 2944 cur_port->acm_intr_ph, 2945 USB_FLAGS_SLEEP); 2946 mutex_enter(&acmp->acm_mutex); 2947 2948 mutex_enter(&cur_port->acm_port_mutex); 2949 cur_port->acm_intr_state = 2950 USBSACM_PIPE_IDLE; 2951 mutex_exit(&cur_port->acm_port_mutex); 2952 } 2953 } 2954 } 2955 2956 acmp->acm_dev_state = USB_DEV_PWRED_DOWN; 2957 acmp->acm_pm->pm_cur_power = USB_DEV_OS_PWR_OFF; 2958 2959 /* FALLTHRU */ 2960 case USB_DEV_DISCONNECTED: 2961 case USB_DEV_SUSPENDED: 2962 /* allow a disconnect/cpr'ed device to go to lower power */ 2963 2964 return (USB_SUCCESS); 2965 case USB_DEV_PWRED_DOWN: 2966 default: 2967 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 2968 "usbsacm_pwrlvl0: illegal device state"); 2969 2970 return (USB_FAILURE); 2971 } 2972 } 2973 2974 2975 /* 2976 * usbsacm_pwrlvl1: 2977 * Functions to handle power transition for OS levels 1 -> 2 2978 */ 2979 static int 2980 usbsacm_pwrlvl1(usbsacm_state_t *acmp) 2981 { 2982 /* issue USB D2 command to the device */ 2983 (void) usb_set_device_pwrlvl2(acmp->acm_dip); 2984 2985 return (USB_FAILURE); 2986 } 2987 2988 2989 /* 2990 * usbsacm_pwrlvl2: 2991 * Functions to handle power transition for OS levels 2 -> 1 2992 */ 2993 static int 2994 usbsacm_pwrlvl2(usbsacm_state_t *acmp) 2995 { 2996 /* issue USB D1 command to the device */ 2997 (void) usb_set_device_pwrlvl1(acmp->acm_dip); 2998 2999 return (USB_FAILURE); 3000 } 3001 3002 3003 /* 3004 * usbsacm_pwrlvl3: 3005 * Functions to handle power transition for OS levels 3 -> 0 3006 * The same level as OS state, different from USB state 3007 */ 3008 static int 3009 usbsacm_pwrlvl3(usbsacm_state_t *acmp) 3010 { 3011 int rval; 3012 int i; 3013 usbsacm_port_t *cur_port = acmp->acm_ports; 3014 3015 USB_DPRINTF_L4(PRINT_MASK_PM, acmp->acm_lh, 3016 "usbsacm_pwrlvl3: "); 3017 3018 switch (acmp->acm_dev_state) { 3019 case USB_DEV_PWRED_DOWN: 3020 /* Issue USB D0 command to the device here */ 3021 rval = usb_set_device_pwrlvl0(acmp->acm_dip); 3022 ASSERT(rval == USB_SUCCESS); 3023 3024 if (cur_port != NULL) { 3025 for (i = 0; i < acmp->acm_port_cnt; i++) { 3026 cur_port = &acmp->acm_ports[i]; 3027 if (cur_port->acm_intr_ph != NULL && 3028 cur_port->acm_port_state != 3029 USBSACM_PORT_CLOSED) { 3030 3031 mutex_exit(&acmp->acm_mutex); 3032 usbsacm_pipe_start_polling(cur_port); 3033 mutex_enter(&acmp->acm_mutex); 3034 } 3035 } 3036 } 3037 3038 acmp->acm_dev_state = USB_DEV_ONLINE; 3039 acmp->acm_pm->pm_cur_power = USB_DEV_OS_FULL_PWR; 3040 3041 /* FALLTHRU */ 3042 case USB_DEV_ONLINE: 3043 /* we are already in full power */ 3044 3045 /* FALLTHRU */ 3046 case USB_DEV_DISCONNECTED: 3047 case USB_DEV_SUSPENDED: 3048 3049 return (USB_SUCCESS); 3050 default: 3051 USB_DPRINTF_L2(PRINT_MASK_PM, acmp->acm_lh, 3052 "usbsacm_pwrlvl3: illegal device state"); 3053 3054 return (USB_FAILURE); 3055 } 3056 } 3057 3058 3059 /* 3060 * usbsacm_pipe_start_polling: 3061 * start polling on the interrupt pipe 3062 */ 3063 static void 3064 usbsacm_pipe_start_polling(usbsacm_port_t *acm_port) 3065 { 3066 usb_intr_req_t *intr; 3067 int rval; 3068 usbsacm_state_t *acmp = acm_port->acm_device; 3069 3070 USB_DPRINTF_L4(PRINT_MASK_ATTA, acmp->acm_lh, 3071 "usbsacm_pipe_start_polling: "); 3072 3073 if (acm_port->acm_intr_ph == NULL) { 3074 3075 return; 3076 } 3077 3078 intr = usb_alloc_intr_req(acmp->acm_dip, 0, USB_FLAGS_SLEEP); 3079 3080 /* 3081 * If it is in interrupt context, usb_alloc_intr_req will return NULL if 3082 * called with SLEEP flag. 3083 */ 3084 if (!intr) { 3085 USB_DPRINTF_L2(PRINT_MASK_OPEN, acmp->acm_lh, 3086 "usbsacm_pipe_start_polling: alloc req failed."); 3087 3088 return; 3089 } 3090 3091 /* initialize the interrupt request. */ 3092 intr->intr_attributes = USB_ATTRS_SHORT_XFER_OK | 3093 USB_ATTRS_AUTOCLEARING; 3094 mutex_enter(&acm_port->acm_port_mutex); 3095 intr->intr_len = acm_port->acm_intr_ep_descr.wMaxPacketSize; 3096 mutex_exit(&acm_port->acm_port_mutex); 3097 intr->intr_client_private = (usb_opaque_t)acm_port; 3098 intr->intr_cb = usbsacm_intr_cb; 3099 intr->intr_exc_cb = usbsacm_intr_ex_cb; 3100 3101 rval = usb_pipe_intr_xfer(acm_port->acm_intr_ph, intr, USB_FLAGS_SLEEP); 3102 3103 mutex_enter(&acm_port->acm_port_mutex); 3104 if (rval == USB_SUCCESS) { 3105 acm_port->acm_intr_state = USBSACM_PIPE_BUSY; 3106 } else { 3107 usb_free_intr_req(intr); 3108 acm_port->acm_intr_state = USBSACM_PIPE_IDLE; 3109 USB_DPRINTF_L3(PRINT_MASK_OPEN, acmp->acm_lh, 3110 "usbsacm_pipe_start_polling: failed (%d)", rval); 3111 } 3112 mutex_exit(&acm_port->acm_port_mutex); 3113 } 3114 3115 3116 /* 3117 * usbsacm_intr_cb: 3118 * interrupt pipe normal callback 3119 */ 3120 /*ARGSUSED*/ 3121 static void 3122 usbsacm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req) 3123 { 3124 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->intr_client_private; 3125 usbsacm_state_t *acmp = acm_port->acm_device; 3126 mblk_t *data = req->intr_data; 3127 int data_len; 3128 3129 USB_DPRINTF_L4(PRINT_MASK_CB, acmp->acm_lh, 3130 "usbsacm_intr_cb: "); 3131 3132 data_len = (data) ? MBLKL(data) : 0; 3133 3134 /* check data length */ 3135 if (data_len < 8) { 3136 USB_DPRINTF_L2(PRINT_MASK_CB, acmp->acm_lh, 3137 "usbsacm_intr_cb: %d packet too short", data_len); 3138 usb_free_intr_req(req); 3139 3140 return; 3141 } 3142 req->intr_data = NULL; 3143 usb_free_intr_req(req); 3144 3145 mutex_enter(&acm_port->acm_port_mutex); 3146 /* parse interrupt data. */ 3147 usbsacm_parse_intr_data(acm_port, data); 3148 mutex_exit(&acm_port->acm_port_mutex); 3149 } 3150 3151 3152 /* 3153 * usbsacm_intr_ex_cb: 3154 * interrupt pipe exception callback 3155 */ 3156 /*ARGSUSED*/ 3157 static void 3158 usbsacm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req) 3159 { 3160 usbsacm_port_t *acm_port = (usbsacm_port_t *)req->intr_client_private; 3161 usbsacm_state_t *acmp = acm_port->acm_device; 3162 usb_cr_t cr = req->intr_completion_reason; 3163 3164 USB_DPRINTF_L4(PRINT_MASK_CB, acmp->acm_lh, 3165 "usbsacm_intr_ex_cb: "); 3166 3167 usb_free_intr_req(req); 3168 3169 /* 3170 * If completion reason isn't USB_CR_PIPE_CLOSING and 3171 * USB_CR_STOPPED_POLLING, restart polling. 3172 */ 3173 if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING)) { 3174 mutex_enter(&acmp->acm_mutex); 3175 3176 if (acmp->acm_dev_state != USB_DEV_ONLINE) { 3177 3178 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3179 "usbsacm_intr_ex_cb: state = %d", 3180 acmp->acm_dev_state); 3181 3182 mutex_exit(&acmp->acm_mutex); 3183 3184 return; 3185 } 3186 mutex_exit(&acmp->acm_mutex); 3187 3188 usbsacm_pipe_start_polling(acm_port); 3189 } 3190 } 3191 3192 3193 /* 3194 * usbsacm_parse_intr_data: 3195 * Parse data received from interrupt callback 3196 */ 3197 static void 3198 usbsacm_parse_intr_data(usbsacm_port_t *acm_port, mblk_t *data) 3199 { 3200 usbsacm_state_t *acmp = acm_port->acm_device; 3201 uint8_t bmRequestType; 3202 uint8_t bNotification; 3203 uint16_t wValue; 3204 uint16_t wLength; 3205 uint16_t wData; 3206 3207 USB_DPRINTF_L4(PRINT_MASK_ALL, acmp->acm_lh, 3208 "usbsacm_parse_intr_data: "); 3209 3210 bmRequestType = data->b_rptr[0]; 3211 bNotification = data->b_rptr[1]; 3212 /* 3213 * If Notification type is NETWORK_CONNECTION, wValue is 0 or 1, 3214 * mLength is 0. If Notification type is SERIAL_TYPE, mValue is 0, 3215 * mLength is 2. So we directly get the value from the byte. 3216 */ 3217 wValue = data->b_rptr[2]; 3218 wLength = data->b_rptr[6]; 3219 3220 if (bmRequestType != USB_CDC_NOTIFICATION_REQUEST_TYPE) { 3221 USB_DPRINTF_L2(PRINT_MASK_CB, acmp->acm_lh, 3222 "usbsacm_parse_intr_data: unknown request type - 0x%x", 3223 bmRequestType); 3224 3225 freemsg(data); 3226 3227 return; 3228 } 3229 3230 /* 3231 * Check the return value of device 3232 */ 3233 switch (bNotification) { 3234 case USB_CDC_NOTIFICATION_NETWORK_CONNECTION: 3235 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3236 "usbsacm_parse_intr_data: %s network!", 3237 wValue ? "connected to" :"disconnected from"); 3238 3239 break; 3240 case USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE: 3241 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3242 "usbsacm_parse_intr_data: A response is a available."); 3243 3244 break; 3245 case USB_CDC_NOTIFICATION_SERIAL_STATE: 3246 /* check the parameter's length. */ 3247 if (wLength != 2) { 3248 3249 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3250 "usbsacm_parse_intr_data: error data length."); 3251 } else { 3252 /* 3253 * The Data field is a bitmapped value that contains 3254 * the current state of carrier detect, transmission 3255 * carrier, break, ring signal and device overrun 3256 * error. 3257 */ 3258 wData = data->b_rptr[8]; 3259 /* 3260 * Check the serial state of the current port. 3261 */ 3262 if (wData & USB_CDC_ACM_CONTROL_DCD) { 3263 3264 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3265 "usbsacm_parse_intr_data: " 3266 "receiver carrier is set."); 3267 } 3268 if (wData & USB_CDC_ACM_CONTROL_DSR) { 3269 3270 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3271 "usbsacm_parse_intr_data: " 3272 "transmission carrier is set."); 3273 3274 acm_port->acm_mctlin |= USB_CDC_ACM_CONTROL_DSR; 3275 } 3276 if (wData & USB_CDC_ACM_CONTROL_BREAK) { 3277 3278 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3279 "usbsacm_parse_intr_data: " 3280 "break detection mechanism is set."); 3281 } 3282 if (wData & USB_CDC_ACM_CONTROL_RNG) { 3283 3284 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3285 "usbsacm_parse_intr_data: " 3286 "ring signal detection is set."); 3287 3288 acm_port->acm_mctlin |= USB_CDC_ACM_CONTROL_RNG; 3289 } 3290 if (wData & USB_CDC_ACM_CONTROL_FRAMING) { 3291 3292 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3293 "usbsacm_parse_intr_data: " 3294 "A framing error has occurred."); 3295 } 3296 if (wData & USB_CDC_ACM_CONTROL_PARITY) { 3297 3298 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3299 "usbsacm_parse_intr_data: " 3300 "A parity error has occurred."); 3301 } 3302 if (wData & USB_CDC_ACM_CONTROL_OVERRUN) { 3303 3304 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3305 "usbsacm_parse_intr_data: " 3306 "Received data has been discarded " 3307 "due to overrun."); 3308 } 3309 } 3310 3311 break; 3312 default: 3313 USB_DPRINTF_L3(PRINT_MASK_CB, acmp->acm_lh, 3314 "usbsacm_parse_intr_data: unknown notification - 0x%x!", 3315 bNotification); 3316 3317 break; 3318 } 3319 3320 freemsg(data); 3321 } 3322