xref: /illumos-gate/usr/src/uts/common/sys/usb/clients/usbser/usbser_var.h (revision bfed486ad8de8b8ebc6345a8e10accae08bf2f45)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #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 /*
243  * is the port opening?
244  */
245 #define	USBSER_IS_OPENING(pp)	\
246 	(((pp)->port_state == USBSER_PORT_OPENING_TTY) || \
247 	((pp)->port_state == USBSER_PORT_OPENING_OUT))
248 
249 /*
250  * determine, while we are trying to open the port,
251  * whether it is currently being open in the opposite mode
252  */
253 #define	USBSER_NO_OTHER_OPEN(pp, minor)	\
254 	((((minor) & OUTLINE) &&	\
255 	((pp)->port_state == USBSER_PORT_OPENING_OUT)) ||	\
256 	(!((minor) & OUTLINE) && ((pp)->port_state == USBSER_PORT_OPENING_TTY)))
257 
258 /*
259  * determine, while we are trying to open the port,
260  * whether it is already open in the opposite mode
261  */
262 #define	USBSER_OPEN_IN_OTHER_MODE(pp, minor)	\
263 	((((minor) & OUTLINE) && !((pp)->port_flags & USBSER_FL_OUT)) || \
264 	(!((minor) & OUTLINE) && ((pp)->port_flags & USBSER_FL_OUT)))
265 
266 /*
267  * minor number manipulation
268  */
269 enum {
270 	MAXPORTS_PER_DEVICE_SHIFT	= 4,
271 	MAXPORTS_PER_DEVICE		= (1 << MAXPORTS_PER_DEVICE_SHIFT),
272 	MAXPORTS_PER_DEVICE_MASK	= (MAXPORTS_PER_DEVICE - 1),
273 	OUTLINE				= (1 << (NBITSMINOR32 - 1))
274 };
275 
276 #define	USBSER_MAKEMINOR(instance, port, outline)	\
277 		((port) | ((instance) << MAXPORTS_PER_DEVICE_SHIFT) | (outline))
278 
279 #define	USBSER_MINOR2INST(minor)	\
280 	(((minor) & ~(OUTLINE | MAXPORTS_PER_DEVICE_MASK)) \
281 	>> MAXPORTS_PER_DEVICE_SHIFT)
282 
283 #define	USBSER_MINOR2PORT(minor)	((minor) & MAXPORTS_PER_DEVICE_MASK)
284 
285 /*
286  * various tunables
287  *
288  * timeouts are in seconds
289  */
290 enum {
291 	USBSER_TX_FIFO_DRAIN_TIMEOUT	= 5, /* tx fifo drain timeout */
292 	USBSER_WQ_DRAIN_TIMEOUT		= 2, /* wq drain timeout */
293 	USBSER_SUSPEND_TIMEOUT		= 10 /* cpr suspend timeout */
294 };
295 
296 /*
297  * debug printing masks
298  */
299 #define	DPRINT_ATTACH		0x00000001
300 #define	DPRINT_DETACH		0x00000002
301 #define	DPRINT_OPEN		0x00000004
302 #define	DPRINT_CLOSE		0x00000008
303 #define	DPRINT_WQ		0x00000010
304 #define	DPRINT_RQ		0x00000020
305 #define	DPRINT_IOCTL		0x00000040
306 #define	DPRINT_RX_CB		0x00000100
307 #define	DPRINT_TX_CB		0x00000200
308 #define	DPRINT_STATUS_CB	0x00000400
309 #define	DPRINT_EVENTS		0x00001000
310 #define	DPRINT_CPR		0x00002000
311 #define	DPRINT_MASK_ALL		0xFFFFFFFF
312 
313 /*
314  * misc macros
315  */
316 #define	NELEM(a)	(sizeof (a) / sizeof (*(a)))
317 
318 /*
319  * shortcuts to DSD operations
320  */
321 #define	USBSER_DS_ATTACH(usp, aip)	usp->us_ds_ops->ds_attach(aip)
322 
323 #define	USBSER_DS_DETACH(usp)	usp->us_ds_ops->ds_detach(usp->us_ds_hdl)
324 
325 #define	USBSER_DS_OPEN_PORT(usp, port_num)	\
326 	usp->us_ds_ops->ds_open_port(usp->us_ds_hdl, port_num)
327 
328 #define	USBSER_DS_CLOSE_PORT(usp, port_num)	\
329 	usp->us_ds_ops->ds_close_port(usp->us_ds_hdl, port_num)
330 
331 #define	USBSER_DS_REGISTER_CB(usp, port_num, cb)	\
332 	usp->us_ds_ops->ds_register_cb(usp->us_ds_hdl, port_num, cb)
333 
334 #define	USBSER_DS_UNREGISTER_CB(usp, port_num)	\
335 	usp->us_ds_ops->ds_unregister_cb(usp->us_ds_hdl, port_num)
336 
337 /* power management */
338 #define	USBSER_DS_USB_POWER(usp, comp, level, new_statep)	\
339 	usp->us_ds_ops->ds_usb_power(usp->us_ds_hdl, comp, level, new_statep)
340 
341 #define	USBSER_DS_SUSPEND(usp)	usp->us_ds_ops->ds_suspend(usp->us_ds_hdl)
342 
343 #define	USBSER_DS_RESUME(usp)	usp->us_ds_ops->ds_resume(usp->us_ds_hdl)
344 
345 #define	USBSER_DS_DISCONNECT(usp) usp->us_ds_ops->ds_disconnect(usp->us_ds_hdl)
346 
347 #define	USBSER_DS_RECONNECT(usp) usp->us_ds_ops->ds_reconnect(usp->us_ds_hdl)
348 
349 /* standard UART operations */
350 #define	USBSER_DS_SET_PORT_PARAMS(pp, params)	\
351 	pp->port_ds_ops->ds_set_port_params(pp->port_ds_hdl, pp->port_num, \
352 		params)
353 
354 #define	USBSER_DS_SET_MODEM_CTL(pp, mask, val)	\
355 	pp->port_ds_ops->ds_set_modem_ctl(pp->port_ds_hdl, pp->port_num, mask, \
356 		val)
357 
358 #define	USBSER_DS_GET_MODEM_CTL(pp, mask, valp)	\
359 	pp->port_ds_ops->ds_get_modem_ctl(pp->port_ds_hdl, pp->port_num, \
360 		mask, valp)
361 
362 #define	USBSER_DS_BREAK_CTL(pp, val)		\
363 	pp->port_ds_ops->ds_break_ctl(pp->port_ds_hdl, pp->port_num, val)
364 
365 #define	USBSER_DS_LOOPBACK(pp, val)		\
366 	pp->port_ds_ops->ds_loopback(pp->port_ds_hdl, pp->port_num, val)
367 
368 /* data xfer */
369 #define	USBSER_DS_TX(pp, mp)		\
370 	pp->port_ds_ops->ds_tx(pp->port_ds_hdl, pp->port_num, mp)
371 
372 #define	USBSER_DS_RX(pp)		\
373 	pp->port_ds_ops->ds_rx(pp->port_ds_hdl, pp->port_num)
374 
375 #define	USBSER_DS_STOP(pp, dir)		\
376 	pp->port_ds_ops->ds_stop(pp->port_ds_hdl, pp->port_num, dir)
377 
378 #define	USBSER_DS_START(pp, dir)	\
379 	pp->port_ds_ops->ds_start(pp->port_ds_hdl, pp->port_num, dir)
380 
381 /* fifos */
382 #define	USBSER_DS_FIFO_FLUSH(pp, mask)		\
383 	pp->port_ds_ops->ds_fifo_flush(pp->port_ds_hdl, pp->port_num, mask)
384 
385 #define	USBSER_DS_FIFO_DRAIN(pp, tmout)		\
386 	pp->port_ds_ops->ds_fifo_drain(pp->port_ds_hdl, pp->port_num, tmout)
387 
388 
389 /* check for supported operations */
390 #define	USBSER_DS_LOOPBACK_SUPPORTED(pp) (pp->port_ds_ops->ds_loopback != 0)
391 
392 #ifdef	__cplusplus
393 }
394 #endif
395 
396 #endif	/* _SYS_USB_USBSER_VAR_H */
397