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