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(4D) 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