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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #ifndef _SYS_USB_USBSER_VAR_H 27 #define _SYS_USB_USBSER_VAR_H 28 29 30 /* 31 * USB-to-serial driver definitions 32 */ 33 34 #include <sys/tty.h> 35 #include <sys/mkdev.h> 36 #include <sys/sunddi.h> 37 #include <sys/note.h> 38 39 #include <sys/usb/clients/usbser/usbser_dsdi.h> 40 41 #ifdef __cplusplus 42 extern "C" { 43 #endif 44 45 typedef struct usbser_state usbser_state_t; 46 typedef struct usbser_port usbser_port_t; 47 48 /* 49 * because put() and srv() routines are not allowed to block, usbser 50 * provides each port with two threads: for read and write processing 51 * this structure describes the data associated with a usbser thread 52 */ 53 typedef struct usbser_thread { 54 kcondvar_t thr_cv; /* cv for request wait */ 55 uint_t thr_flags; /* state flags */ 56 usbser_port_t *thr_port; /* port owner of this thread */ 57 void (*thr_func)(void *); /* function to be run */ 58 void *thr_arg; /* function argument */ 59 } usbser_thread_t; 60 61 /* 62 * thr_flags 63 */ 64 enum { 65 USBSER_THR_RUNNING = 0x01, /* thread is running */ 66 USBSER_THR_WAKE = 0x02, /* wake requested */ 67 USBSER_THR_EXITED = 0x04 /* thread exited */ 68 }; 69 70 /* 71 * additional device state 72 */ 73 #define USBSER_DEV_INIT 0x80 /* device is being initialized */ 74 75 /* 76 * per instance data 77 */ 78 struct usbser_state { 79 struct usbser_state *us_next; /* linked list */ 80 dev_info_t *us_dip; /* device information */ 81 kmutex_t us_mutex; /* structure lock */ 82 void *us_statep; /* soft state anchor */ 83 int us_instance; /* instance number */ 84 ds_ops_t *us_ds_ops; /* DSD operations */ 85 ds_hdl_t us_ds_hdl; /* DSD device handle */ 86 uint_t us_port_cnt; /* port count */ 87 usbser_port_t *us_ports; /* array of port structs */ 88 uint_t us_dev_state; /* USB device state */ 89 usb_log_handle_t us_lh; /* USB log handle */ 90 ddi_taskq_t *us_taskq; /* taskq for command handling */ 91 }; 92 93 _NOTE(MUTEX_PROTECTS_DATA(usbser_state::us_mutex, usbser_state::us_dev_state)) 94 95 /* 96 * per port data 97 */ 98 struct usbser_port { 99 kmutex_t port_mutex; /* structure lock */ 100 usbser_state_t *port_usp; /* back pointer to state */ 101 char port_lh_name[16]; /* log handle name */ 102 usb_log_handle_t port_lh; /* log handle */ 103 ds_ops_t *port_ds_ops; /* copy from usbser_state */ 104 ds_hdl_t port_ds_hdl; /* copy from usbser_state */ 105 uint_t port_num; /* port number */ 106 uint_t port_state; /* port state */ 107 uint_t port_act; /* current activities on port */ 108 uint_t port_flags; /* port flags */ 109 kcondvar_t port_state_cv; /* port state cv */ 110 kcondvar_t port_act_cv; /* port activity cv */ 111 kcondvar_t port_car_cv; /* port carrier cv */ 112 uint_t port_wq_data_cnt; /* amount of unsent data */ 113 usbser_thread_t port_wq_thread; /* wq thread */ 114 usbser_thread_t port_rq_thread; /* rq thread */ 115 tty_common_t port_ttycommon; /* tty driver common data */ 116 uchar_t port_flowc; /* flow control char */ 117 timeout_id_t port_delay_id; /* delay/break timeout id */ 118 }; 119 120 _NOTE(MUTEX_PROTECTS_DATA(usbser_port::port_mutex, usbser_port)) 121 _NOTE(DATA_READABLE_WITHOUT_LOCK(usbser_port::{ 122 port_usp 123 port_lh 124 port_ds_ops 125 port_ds_hdl 126 port_num 127 port_ttycommon.t_{readq writeq} 128 })) 129 130 _NOTE(LOCK_ORDER(usbser_state::us_mutex usbser_port::port_mutex)) 131 132 /* 133 * port_state: 134 * 135 * USBSER_PORT_NOT_INIT 136 * | ^ 137 * | | 138 * attach detach 139 * | | 140 * | | +----open[1]----> USBSER_PORT_OPENING_TTY ------+ 141 * | | | | | | 142 * v | | | | | 143 * USBSER_PORT_CLOSED <---device error---< overtake[2] | 144 * | | | | v 145 * | | | v | 146 * | +----open[1]----> USBSER_PORT_OPENING_OUT | 147 * | | | 148 * | | +-------------------+ 149 * | | | 150 * | v v 151 * USBSER_PORT_CLOSING <-----close----- USBSER_PORT_OPEN <-----------+ 152 * ^ | ^ --------+ | 153 * | | | | | 154 * | | | | | 155 * | v | v | 156 * +------close----- USBSER_PORT_DISCONNECTED USBSER_PORT_SUSPENDED 157 * 158 * Notes: 159 * 160 * [1] for each physical port N two device nodes are created: 161 * 162 * /dev/term/N (tty mode) 163 * /dev/cua/N (dial-out mode) 164 * 165 * the port can only be opened in one of these modes at a time. 166 * difference between the two is that in tty mode the driver 167 * will block in open(9E) until the CD (Carrier Detect) pin comes up, 168 * while in dial-out mode CD is ignored. opening and closing states 169 * help to avoid race conditions between two threads trying to open/close 170 * one physical port in two different modes simultaneously. 171 * 172 * [2] tty mode open may be blocked waiting for carrier. 173 * if dial-out mode open happens at this time, it is allowed 174 * for it to overtake the port; from zs(7D) man page: 175 * 176 * This allows a modem to be attached to /dev/term/[n] 177 * and used for dial-in (by enabling the line for login in /etc/inittab) 178 * and also used for dial-out (by tip(1) or uucp(1C)) as /dev/cua/[n] 179 * when no one is logged in on the line. 180 */ 181 enum { 182 USBSER_PORT_NOT_INIT = 0, /* port not initialized */ 183 USBSER_PORT_CLOSED, /* port is closed */ 184 USBSER_PORT_OPENING_TTY, /* tty open in progress */ 185 USBSER_PORT_OPENING_OUT, /* dial-out open in progress */ 186 USBSER_PORT_OPEN, /* port is open */ 187 USBSER_PORT_SUSPENDED, /* port is suspended */ 188 USBSER_PORT_DISCONNECTED, /* port is disconnected */ 189 USBSER_PORT_CLOSING /* close() is in progress */ 190 }; 191 192 /* constants used by state machine implementation */ 193 enum { 194 USBSER_CONTINUE = -1, 195 USBSER_COMPLETE = 0 196 }; 197 198 /* 199 * port_act: current activities on the port. 200 * only one activity of each type is allowed at a time. 201 */ 202 enum { 203 USBSER_ACT_TX = 0x0001, /* transmitting data */ 204 USBSER_ACT_RX = 0x0002, /* receiving data */ 205 USBSER_ACT_CTL = 0x0004, /* controlling the device */ 206 USBSER_ACT_BREAK = 0x0010, /* doing break */ 207 USBSER_ACT_DELAY = 0x0020, /* doing delay */ 208 USBSER_ACT_ALL = 0xffff /* all actions (must be >0) */ 209 }; 210 211 /* 212 * port_flags 213 */ 214 enum { 215 USBSER_FL_OUT = 0x0001, /* dial-out */ 216 USBSER_FL_WOPEN = 0x0002, /* waiting in open() */ 217 USBSER_FL_CARR_ON = 0x0004, /* carrier is on */ 218 USBSER_FL_TX_STOPPED = 0x0008, /* output stopped */ 219 USBSER_FL_RX_STOPPED = 0x0010, /* input stopped */ 220 USBSER_FL_HUNGUP = 0x0020, /* stream is hung up */ 221 USBSER_FL_DSD_OPEN = 0x0040, /* DSD is open */ 222 USBSER_FL_STATUS_CB = 0x0080, /* status callback pending */ 223 USBSER_FL_IGNORE_CD = 0x0100, /* ignore carrier detect */ 224 USBSER_FL_PRESERVE = USBSER_FL_IGNORE_CD 225 /* flags that need to */ 226 /* be preserved across opens */ 227 }; 228 229 /* 230 * current sun compiler does not seem to inline static leaf routines at O3 231 * so we have to use preprocessor macros to make up for compiler disability 232 * 233 * can we access the port? 234 */ 235 #define USBSER_PORT_ACCESS_OK(pp) ((pp)->port_state == USBSER_PORT_OPEN) 236 237 /* 238 * is port doing something? 239 */ 240 #define USBSER_PORT_IS_BUSY(pp) ((pp)->port_act != 0) 241 242 /* port is busy on TX, delay, break, ctrl */ 243 #define USBSER_PORT_IS_BUSY_NON_RX(pp) \ 244 (((pp)->port_act & (USBSER_ACT_DELAY | USBSER_ACT_CTL | \ 245 USBSER_ACT_BREAK | USBSER_ACT_TX)) != 0) 246 247 /* 248 * is the port opening? 249 */ 250 #define USBSER_IS_OPENING(pp) \ 251 (((pp)->port_state == USBSER_PORT_OPENING_TTY) || \ 252 ((pp)->port_state == USBSER_PORT_OPENING_OUT)) 253 254 /* 255 * determine, while we are trying to open the port, 256 * whether it is currently being open in the opposite mode 257 */ 258 #define USBSER_NO_OTHER_OPEN(pp, minor) \ 259 ((((minor) & OUTLINE) && \ 260 ((pp)->port_state == USBSER_PORT_OPENING_OUT)) || \ 261 (!((minor) & OUTLINE) && ((pp)->port_state == USBSER_PORT_OPENING_TTY))) 262 263 /* 264 * determine, while we are trying to open the port, 265 * whether it is already open in the opposite mode 266 */ 267 #define USBSER_OPEN_IN_OTHER_MODE(pp, minor) \ 268 ((((minor) & OUTLINE) && !((pp)->port_flags & USBSER_FL_OUT)) || \ 269 (!((minor) & OUTLINE) && ((pp)->port_flags & USBSER_FL_OUT))) 270 271 /* 272 * minor number manipulation 273 */ 274 enum { 275 MAXPORTS_PER_DEVICE_SHIFT = 4, 276 MAXPORTS_PER_DEVICE = (1 << MAXPORTS_PER_DEVICE_SHIFT), 277 MAXPORTS_PER_DEVICE_MASK = (MAXPORTS_PER_DEVICE - 1), 278 OUTLINE = (1 << (NBITSMINOR32 - 1)) 279 }; 280 281 #define USBSER_MAKEMINOR(instance, port, outline) \ 282 ((port) | ((instance) << MAXPORTS_PER_DEVICE_SHIFT) | (outline)) 283 284 #define USBSER_MINOR2INST(minor) \ 285 (((minor) & ~(OUTLINE | MAXPORTS_PER_DEVICE_MASK)) \ 286 >> MAXPORTS_PER_DEVICE_SHIFT) 287 288 #define USBSER_MINOR2PORT(minor) ((minor) & MAXPORTS_PER_DEVICE_MASK) 289 290 /* 291 * various tunables 292 * 293 * timeouts are in seconds 294 */ 295 enum { 296 USBSER_TX_FIFO_DRAIN_TIMEOUT = 5, /* tx fifo drain timeout */ 297 USBSER_WQ_DRAIN_TIMEOUT = 2, /* wq drain timeout */ 298 USBSER_SUSPEND_TIMEOUT = 10 /* cpr suspend timeout */ 299 }; 300 301 /* 302 * debug printing masks 303 */ 304 #define DPRINT_ATTACH 0x00000001 305 #define DPRINT_DETACH 0x00000002 306 #define DPRINT_OPEN 0x00000004 307 #define DPRINT_CLOSE 0x00000008 308 #define DPRINT_WQ 0x00000010 309 #define DPRINT_RQ 0x00000020 310 #define DPRINT_IOCTL 0x00000040 311 #define DPRINT_RX_CB 0x00000100 312 #define DPRINT_TX_CB 0x00000200 313 #define DPRINT_STATUS_CB 0x00000400 314 #define DPRINT_EVENTS 0x00001000 315 #define DPRINT_CPR 0x00002000 316 #define DPRINT_MASK_ALL 0xFFFFFFFF 317 318 /* 319 * misc macros 320 */ 321 #define NELEM(a) (sizeof (a) / sizeof (*(a))) 322 323 /* 324 * shortcuts to DSD operations 325 */ 326 #define USBSER_DS_ATTACH(usp, aip) usp->us_ds_ops->ds_attach(aip) 327 328 #define USBSER_DS_DETACH(usp) usp->us_ds_ops->ds_detach(usp->us_ds_hdl) 329 330 #define USBSER_DS_OPEN_PORT(usp, port_num) \ 331 usp->us_ds_ops->ds_open_port(usp->us_ds_hdl, port_num) 332 333 #define USBSER_DS_CLOSE_PORT(usp, port_num) \ 334 usp->us_ds_ops->ds_close_port(usp->us_ds_hdl, port_num) 335 336 #define USBSER_DS_REGISTER_CB(usp, port_num, cb) \ 337 usp->us_ds_ops->ds_register_cb(usp->us_ds_hdl, port_num, cb) 338 339 #define USBSER_DS_UNREGISTER_CB(usp, port_num) \ 340 usp->us_ds_ops->ds_unregister_cb(usp->us_ds_hdl, port_num) 341 342 /* power management */ 343 #define USBSER_DS_USB_POWER(usp, comp, level, new_statep) \ 344 usp->us_ds_ops->ds_usb_power(usp->us_ds_hdl, comp, level, new_statep) 345 346 #define USBSER_DS_SUSPEND(usp) usp->us_ds_ops->ds_suspend(usp->us_ds_hdl) 347 348 #define USBSER_DS_RESUME(usp) usp->us_ds_ops->ds_resume(usp->us_ds_hdl) 349 350 #define USBSER_DS_DISCONNECT(usp) usp->us_ds_ops->ds_disconnect(usp->us_ds_hdl) 351 352 #define USBSER_DS_RECONNECT(usp) usp->us_ds_ops->ds_reconnect(usp->us_ds_hdl) 353 354 /* standard UART operations */ 355 #define USBSER_DS_SET_PORT_PARAMS(pp, params) \ 356 pp->port_ds_ops->ds_set_port_params(pp->port_ds_hdl, pp->port_num, \ 357 params) 358 359 #define USBSER_DS_SET_MODEM_CTL(pp, mask, val) \ 360 pp->port_ds_ops->ds_set_modem_ctl(pp->port_ds_hdl, pp->port_num, mask, \ 361 val) 362 363 #define USBSER_DS_GET_MODEM_CTL(pp, mask, valp) \ 364 pp->port_ds_ops->ds_get_modem_ctl(pp->port_ds_hdl, pp->port_num, \ 365 mask, valp) 366 367 #define USBSER_DS_BREAK_CTL(pp, val) \ 368 pp->port_ds_ops->ds_break_ctl(pp->port_ds_hdl, pp->port_num, val) 369 370 #define USBSER_DS_LOOPBACK(pp, val) \ 371 pp->port_ds_ops->ds_loopback(pp->port_ds_hdl, pp->port_num, val) 372 373 /* data xfer */ 374 #define USBSER_DS_TX(pp, mp) \ 375 pp->port_ds_ops->ds_tx(pp->port_ds_hdl, pp->port_num, mp) 376 377 #define USBSER_DS_RX(pp) \ 378 pp->port_ds_ops->ds_rx(pp->port_ds_hdl, pp->port_num) 379 380 #define USBSER_DS_STOP(pp, dir) \ 381 pp->port_ds_ops->ds_stop(pp->port_ds_hdl, pp->port_num, dir) 382 383 #define USBSER_DS_START(pp, dir) \ 384 pp->port_ds_ops->ds_start(pp->port_ds_hdl, pp->port_num, dir) 385 386 /* fifos */ 387 #define USBSER_DS_FIFO_FLUSH(pp, mask) \ 388 pp->port_ds_ops->ds_fifo_flush(pp->port_ds_hdl, pp->port_num, mask) 389 390 #define USBSER_DS_FIFO_DRAIN(pp, tmout) \ 391 pp->port_ds_ops->ds_fifo_drain(pp->port_ds_hdl, pp->port_num, tmout) 392 393 394 /* check for supported operations */ 395 #define USBSER_DS_LOOPBACK_SUPPORTED(pp) (pp->port_ds_ops->ds_loopback != 0) 396 397 #ifdef __cplusplus 398 } 399 #endif 400 401 #endif /* _SYS_USB_USBSER_VAR_H */ 402