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