xref: /illumos-gate/usr/src/uts/common/sys/asy.h (revision 8f4696068ddd989ae2e241a1bfc977d29bb00c84)
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 /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
23 /*	  All Rights Reserved	*/
24 
25 /*
26  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
27  * Copyright 2023 Oxide Computer Company
28  * Copyright 2024 Hans Rosenfeld
29  */
30 
31 #ifndef	_SYS_ASY_H
32 #define	_SYS_ASY_H
33 
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37 
38 #include <sys/tty.h>
39 #include <sys/ksynch.h>
40 #include <sys/dditypes.h>
41 
42 /*
43  * internal bus type naming
44  */
45 #define	ASY_BUS_PCI	(0)
46 #define	ASY_BUS_ISA	(1)
47 #define	ASY_BUS_UNKNOWN	(-1)
48 
49 #define	ASY_MINOR_LEN	(40)
50 
51 #define	COM1_IOADDR	0x3f8
52 #define	COM2_IOADDR	0x2f8
53 #define	COM3_IOADDR	0x3e8
54 #define	COM4_IOADDR	0x2e8
55 
56 /*
57  * Definitions for INS8250 / 16550  chips
58  */
59 
60 /* defined as offsets from the data register */
61 #define	DAT		0	/* receive/transmit data */
62 #define	ICR		1	/* interrupt control register */
63 #define	ISR		2	/* interrupt status register */
64 #define	LCR		3	/* line control register */
65 #define	MCR		4	/* modem control register */
66 #define	LSR		5	/* line status register */
67 #define	MSR		6	/* modem status register */
68 #define	SCR		7	/* scratch register */
69 #define	DLL		0	/* divisor latch (lsb) */
70 #define	DLH		1	/* divisor latch (msb) */
71 #define	FIFOR		ISR	/* FIFO register for 16550 */
72 #define	EFR		ISR	/* Enhanced feature register for 16650 */
73 
74 /*
75  * INTEL 8210-A/B & 16450/16550 Registers Structure.
76  */
77 
78 /* Line Control Register */
79 #define	WLS0		0x01	/* word length select bit 0 */
80 #define	WLS1		0x02	/* word length select bit 2 */
81 #define	STB		0x04	/* number of stop bits */
82 #define	PEN		0x08	/* parity enable */
83 #define	EPS		0x10	/* even parity select */
84 #define	SETBREAK	0x40	/* break key */
85 #define	DLAB		0x80	/* divisor latch access bit */
86 #define	RXLEN		0x03	/* # of data bits per received/xmitted char */
87 #define	STOP1		0x00
88 #define	STOP2		0x04
89 #define	PAREN		0x08
90 #define	PAREVN		0x10
91 #define	PARMARK		0x20
92 #define	SNDBRK		0x40
93 #define	EFRACCESS	0xBF	/* magic value for 16650 EFR access */
94 
95 #define	BITS5		0x00	/* 5 bits per char */
96 #define	BITS6		0x01	/* 6 bits per char */
97 #define	BITS7		0x02	/* 7 bits per char */
98 #define	BITS8		0x03	/* 8 bits per char */
99 
100 /* Line Status Register */
101 #define	RCA		0x01	/* data ready */
102 #define	OVRRUN		0x02	/* overrun error */
103 #define	PARERR		0x04	/* parity error */
104 #define	FRMERR		0x08	/* framing error */
105 #define	BRKDET		0x10	/* a break has arrived */
106 #define	XHRE		0x20	/* tx hold reg is now empty */
107 #define	XSRE		0x40	/* tx shift reg is now empty */
108 #define	RFBE		0x80	/* rx FIFO Buffer error */
109 
110 /* Interrupt Id Regisger */
111 #define	MSTATUS		0x00	/* modem status changed */
112 #define	NOINTERRUPT	0x01	/* no interrupt pending */
113 #define	TxRDY		0x02	/* Transmitter Holding Register Empty */
114 #define	RxRDY		0x04	/* Receiver Data Available */
115 #define	FFTMOUT		0x0c	/* FIFO timeout - 16550AF */
116 #define	RSTATUS		0x06	/* Receiver Line Status */
117 
118 /* Interrupt Enable Register */
119 #define	RIEN		0x01	/* Received Data Ready */
120 #define	TIEN		0x02	/* Tx Hold Register Empty */
121 #define	SIEN		0x04	/* Receiver Line Status */
122 #define	MIEN		0x08	/* Modem Status */
123 
124 /* Modem Control Register */
125 #define	DTR		0x01	/* Data Terminal Ready */
126 #define	RTS		0x02	/* Request To Send */
127 #define	OUT1		0x04	/* Aux output - not used */
128 #define	OUT2		0x08	/* turns intr to 386 on/off */
129 #define	ASY_LOOP	0x10	/* loopback for diagnostics */
130 
131 /* Modem Status Register */
132 #define	DCTS		0x01	/* Delta Clear To Send */
133 #define	DDSR		0x02	/* Delta Data Set Ready */
134 #define	DRI		0x04	/* Trail Edge Ring Indicator */
135 #define	DDCD		0x08	/* Delta Data Carrier Detect */
136 #define	CTS		0x10	/* Clear To Send */
137 #define	DSR		0x20	/* Data Set Ready */
138 #define	RI		0x40	/* Ring Indicator */
139 #define	DCD		0x80	/* Data Carrier Detect */
140 
141 #define	DELTAS(x)	((x)&(DCTS|DDSR|DRI|DDCD))
142 #define	STATES(x)	((x)&(CTS|DSR|RI|DCD))
143 
144 /* flags for FCR (FIFO Control register) */
145 #define	FIFO_OFF	0x00	/* fifo disabled */
146 #define	FIFO_ON		0x01	/* fifo enabled */
147 #define	FIFORXFLSH	0x02	/* flush receiver FIFO */
148 #define	FIFOTXFLSH	0x04	/* flush transmitter FIFO */
149 #define	FIFODMA		0x08	/* DMA mode 1 */
150 #define	FIFOEXTRA1	0x10	/* Longer fifos on some 16650's */
151 #define	FIFOEXTRA2	0x20	/* Longer fifos on some 16650's and 16750 */
152 #define	FIFO_TRIG_1	0x00	/* 1 byte trigger level */
153 #define	FIFO_TRIG_4	0x40	/* 4 byte trigger level */
154 #define	FIFO_TRIG_8	0x80	/* 8 byte trigger level */
155 #define	FIFO_TRIG_14	0xC0	/* 14 byte trigger level */
156 
157 /* Serial in/out requests */
158 
159 #define	OVERRUN		040000
160 #define	FRERROR		020000
161 #define	PERROR		010000
162 #define	S_ERRORS	(PERROR|OVERRUN|FRERROR)
163 
164 /* EFR - Enhanced feature register for 16650 */
165 #define	ENHENABLE	0x10
166 
167 /* SCR - scratch register */
168 #define	SCRTEST		0x5a	/* arbritrary value for testing SCR register */
169 
170 /*
171  * Ring buffer and async line management definitions.
172  */
173 #define	RINGBITS	16		/* # of bits in ring ptrs */
174 #define	RINGSIZE	(1<<RINGBITS)   /* size of ring */
175 #define	RINGMASK	(RINGSIZE-1)
176 #define	RINGFRAC	12		/* fraction of ring to force flush */
177 
178 #define	RING_INIT(ap)  ((ap)->async_rput = (ap)->async_rget = 0)
179 #define	RING_CNT(ap)   (((ap)->async_rput >= (ap)->async_rget) ? \
180 	((ap)->async_rput - (ap)->async_rget):\
181 	((0x10000 - (ap)->async_rget) + (ap)->async_rput))
182 #define	RING_FRAC(ap)  ((int)RING_CNT(ap) >= (int)(RINGSIZE/RINGFRAC))
183 #define	RING_POK(ap, n) ((int)RING_CNT(ap) < (int)(RINGSIZE-(n)))
184 #define	RING_PUT(ap, c) \
185 	((ap)->async_ring[(ap)->async_rput++ & RINGMASK] =  (uchar_t)(c))
186 #define	RING_UNPUT(ap) ((ap)->async_rput--)
187 #define	RING_GOK(ap, n) ((int)RING_CNT(ap) >= (int)(n))
188 #define	RING_GET(ap)   ((ap)->async_ring[(ap)->async_rget++ & RINGMASK])
189 #define	RING_EAT(ap, n) ((ap)->async_rget += (n))
190 #define	RING_MARK(ap, c, s) \
191 	((ap)->async_ring[(ap)->async_rput++ & RINGMASK] = ((uchar_t)(c)|(s)))
192 #define	RING_UNMARK(ap) \
193 	((ap)->async_ring[((ap)->async_rget) & RINGMASK] &= ~S_ERRORS)
194 #define	RING_ERR(ap, c) \
195 	((ap)->async_ring[((ap)->async_rget) & RINGMASK] & (c))
196 
197 /* definitions for asy_progress */
198 typedef enum {
199 	ASY_PROGRESS_REGS =	0x01,
200 	ASY_PROGRESS_SOFTINT =	0x02,
201 	ASY_PROGRESS_INT =	0x04,
202 	ASY_PROGRESS_MUTEX =	0x08,
203 	ASY_PROGRESS_ASYNC =	0x10,
204 	ASY_PROGRESS_MINOR =	0x20
205 } asy_progress_t;
206 
207 /*
208  * Hardware channel common data. One structure per port.
209  * Each of the fields in this structure is required to be protected by a
210  * mutex lock at the highest priority at which it can be altered.
211  * The asy_flags, and asy_next fields can be altered by interrupt
212  * handling code that must be protected by the mutex whose handle is
213  * stored in asy_excl_hi.  All others can be protected by the asy_excl
214  * mutex, which is lower priority and adaptive.
215  */
216 
217 struct asycom {
218 #ifdef DEBUG
219 	int		asy_debug;	/* per-instance debug flags */
220 #endif
221 	asy_progress_t	asy_progress;	/* attach progress */
222 	int		asy_flags;	/* random flags  */
223 					/* protected by asy_excl_hi lock */
224 	uint_t		asy_hwtype;	/* HW type: ASY16550A, etc. */
225 	uint_t		asy_use_fifo;	/* HW FIFO use it or not ?? */
226 	uint_t		asy_fifo_buf;	/* With FIFO = 16, otherwise = 1 */
227 	uint_t		asy_flags2;	/* flags which don't change, no lock */
228 	uint8_t		*asy_ioaddr;	/* i/o address of ASY port */
229 	struct asyncline *asy_priv;	/* protocol private data -- asyncline */
230 	dev_info_t	*asy_dip;	/* dev_info */
231 	int		asy_unit;	/* which port */
232 	kmutex_t	asy_excl;	/* asy adaptive mutex */
233 	kmutex_t	asy_excl_hi;	/* asy spinlock mutex */
234 	kmutex_t	asy_soft_lock;	/* soft lock for guarding softpend. */
235 	int		asysoftpend;	/* Flag indicating soft int pending. */
236 
237 	ddi_softint_handle_t asy_soft_inth;
238 	uint_t		asy_soft_intr_pri;
239 
240 	ddi_intr_handle_t *asy_inth;
241 	size_t		asy_inth_sz;
242 	uint_t		asy_intr_pri;
243 	int		asy_intr_cnt;
244 	int		asy_intr_cap;
245 	int		asy_intr_type;
246 	int		asy_intr_types;
247 
248 	/*
249 	 * The asy_soft_sr mutex should only be taken by the soft interrupt
250 	 * handler and the driver DDI_SUSPEND/DDI_RESUME code.  It
251 	 * shouldn't be taken by any code that may get called indirectly
252 	 * by the soft interrupt handler (e.g. as a result of a put or
253 	 * putnext call).
254 	 */
255 	kmutex_t	asy_soft_sr;	/* soft int suspend/resume mutex */
256 	uchar_t		asy_msr;	/* saved modem status */
257 	uchar_t		asy_mcr;	/* soft carrier bits */
258 	uchar_t		asy_lcr;	/* console lcr bits */
259 	uchar_t		asy_bidx;	/* console baud rate index */
260 	tcflag_t	asy_cflag;	/* console mode bits */
261 	struct cons_polledio	polledio;	/* polled I/O functions */
262 	ddi_acc_handle_t	asy_iohandle;	/* Data access handle */
263 	tcflag_t	asy_ocflag;	/* old console mode bits */
264 	uchar_t		asy_com_port;	/* COM port number, or zero */
265 	uchar_t		asy_fifor;	/* FIFOR register setting */
266 #ifdef DEBUG
267 	int		asy_msint_cnt;	/* number of times in async_msint */
268 #endif
269 };
270 
271 /*
272  * Asychronous protocol private data structure for ASY.
273  * Each of the fields in the structure is required to be protected by
274  * the lower priority lock except the fields that are set only at
275  * base level but cleared (with out lock) at interrupt level.
276  */
277 
278 struct asyncline {
279 	int		async_flags;	/* random flags */
280 	kcondvar_t	async_flags_cv; /* condition variable for flags */
281 	kcondvar_t	async_ops_cv;	/* condition variable for async_ops */
282 	dev_t		async_dev;	/* device major/minor numbers */
283 	mblk_t		*async_xmitblk;	/* transmit: active msg block */
284 	struct asycom	*async_common;	/* device common data */
285 	tty_common_t	async_ttycommon; /* tty driver common data */
286 	bufcall_id_t	async_wbufcid;	/* id for pending write-side bufcall */
287 	size_t		async_wbufcds;	/* Buffer size requested in bufcall */
288 	timeout_id_t	async_polltid;	/* softint poll timeout id */
289 	timeout_id_t    async_dtrtid;   /* delaying DTR turn on */
290 	timeout_id_t    async_utbrktid; /* hold minimum untimed break time id */
291 
292 	/*
293 	 * The following fields are protected by the asy_excl_hi lock.
294 	 * Some, such as async_flowc, are set only at the base level and
295 	 * cleared (without the lock) only by the interrupt level.
296 	 */
297 	uchar_t		*async_optr;	/* output pointer */
298 	int		async_ocnt;	/* output count */
299 	uint_t		async_rput;	/* producing pointer for input */
300 	uint_t		async_rget;	/* consuming pointer for input */
301 
302 	/*
303 	 * Each character stuffed into the ring has two bytes associated
304 	 * with it.  The first byte is used to indicate special conditions
305 	 * and the second byte is the actual data.  The ring buffer
306 	 * needs to be defined as ushort_t to accomodate this.
307 	 */
308 	ushort_t	async_ring[RINGSIZE];
309 
310 	short		async_break;	/* break count */
311 	int		async_inflow_source; /* input flow control type */
312 
313 	union {
314 		struct {
315 			uchar_t _hw;	/* overrun (hw) */
316 			uchar_t _sw;	/* overrun (sw) */
317 		} _a;
318 		ushort_t uover_overrun;
319 	} async_uover;
320 #define	async_overrun		async_uover._a.uover_overrun
321 #define	async_hw_overrun	async_uover._a._hw
322 #define	async_sw_overrun	async_uover._a._sw
323 	short		async_ext;	/* modem status change count */
324 	short		async_work;	/* work to do flag */
325 	timeout_id_t	async_timer;	/* close drain progress timer */
326 
327 	mblk_t		*async_suspqf;	/* front of suspend queue */
328 	mblk_t		*async_suspqb;	/* back of suspend queue */
329 	int		async_ops;	/* active operations counter */
330 };
331 
332 /* definitions for async_flags field */
333 #define	ASYNC_EXCL_OPEN	 0x10000000	/* exclusive open */
334 #define	ASYNC_WOPEN	 0x00000001	/* waiting for open to complete */
335 #define	ASYNC_ISOPEN	 0x00000002	/* open is complete */
336 #define	ASYNC_OUT	 0x00000004	/* line being used for dialout */
337 #define	ASYNC_CARR_ON	 0x00000008	/* carrier on last time we looked */
338 #define	ASYNC_STOPPED	 0x00000010	/* output is stopped */
339 #define	ASYNC_DELAY	 0x00000020	/* waiting for delay to finish */
340 #define	ASYNC_BREAK	 0x00000040	/* waiting for break to finish */
341 #define	ASYNC_BUSY	 0x00000080	/* waiting for transmission to finish */
342 #define	ASYNC_DRAINING	 0x00000100	/* waiting for output to drain */
343 #define	ASYNC_SERVICEIMM 0x00000200	/* queue soft interrupt as soon as */
344 #define	ASYNC_HW_IN_FLOW 0x00000400	/* input flow control in effect */
345 #define	ASYNC_HW_OUT_FLW 0x00000800	/* output flow control in effect */
346 #define	ASYNC_PROGRESS	 0x00001000	/* made progress on output effort */
347 #define	ASYNC_CLOSING	 0x00002000	/* processing close on stream */
348 #define	ASYNC_OUT_SUSPEND 0x00004000    /* waiting for TIOCSBRK to finish */
349 #define	ASYNC_HOLD_UTBRK 0x00008000	/* waiting for untimed break hold */
350 					/* the minimum time */
351 #define	ASYNC_DTR_DELAY  0x00010000	/* delaying DTR turn on */
352 #define	ASYNC_SW_IN_FLOW 0x00020000	/* sw input flow control in effect */
353 #define	ASYNC_SW_OUT_FLW 0x00040000	/* sw output flow control in effect */
354 #define	ASYNC_SW_IN_NEEDED 0x00080000	/* sw input flow control char is */
355 					/* needed to be sent */
356 #define	ASYNC_OUT_FLW_RESUME 0x00100000 /* output need to be resumed */
357 					/* because of transition of flow */
358 					/* control from stop to start */
359 #define	ASYNC_DDI_SUSPENDED  0x00200000	/* suspended by DDI */
360 #define	ASYNC_RESUME_BUFCALL 0x00400000	/* call bufcall when resumed by DDI */
361 
362 /* asy_hwtype definitions */
363 #define	ASY8250A	0x2		/* 8250A or 16450 */
364 #define	ASY16550	0x3		/* broken FIFO which must not be used */
365 #define	ASY16550A	0x4		/* usable FIFO */
366 #define	ASY16650	0x5
367 #define	ASY16750	0x6
368 
369 /* definitions for asy_flags field */
370 #define	ASY_NEEDSOFT	0x00000001
371 #define	ASY_DOINGSOFT	0x00000002
372 #define	ASY_PPS		0x00000004
373 #define	ASY_PPS_EDGE	0x00000008
374 #define	ASY_DOINGSOFT_RETRY	0x00000010
375 #define	ASY_RTS_DTR_OFF	0x00000020
376 #define	ASY_IGNORE_CD	0x00000040
377 #define	ASY_CONSOLE	0x00000080
378 #define	ASY_DDI_SUSPENDED	0x00000100 /* suspended by DDI */
379 
380 /* definitions for asy_flags2 field */
381 #define	ASY2_NO_LOOPBACK 0x00000001	/* Device doesn't support loopback */
382 
383 /* definitions for async_inflow_source field in struct asyncline */
384 #define	IN_FLOW_NULL	0x00000000
385 #define	IN_FLOW_RINGBUFF	0x00000001
386 #define	IN_FLOW_STREAMS	0x00000002
387 #define	IN_FLOW_USER	0x00000004
388 
389 /*
390  * OUTLINE defines the high-order flag bit in the minor device number that
391  * controls use of a tty line for dialin and dialout simultaneously.
392  */
393 #ifdef _LP64
394 #define	OUTLINE		(1 << (NBITSMINOR32 - 1))
395 #else
396 #define	OUTLINE		(1 << (NBITSMINOR - 1))
397 #endif
398 #define	UNIT(x)		(getminor(x) & ~OUTLINE)
399 
400 /* This corresponds to DDI_SOFTINT_MED used by the old softint routines. */
401 #define	ASY_SOFT_INT_PRI	6
402 
403 
404 #ifdef __cplusplus
405 }
406 #endif
407 
408 #endif	/* _SYS_ASY_H */
409