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