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