xref: /dragonfly/sys/kern/tty_subr.c (revision e26d350b)
1 /*
2  * Copyright (c) 1994, David Greenman
3  * All rights reserved.
4  * Copyright (c) 2003-2011 The DragonFly Project.  All rights reserved.
5  *
6  * This code is derived from software contributed to The DragonFly Project
7   * by Matthew Dillon <dillon@backplane.com>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice unmodified, this list of conditions, and the following
14  *    disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * clist support routines
34  *
35  * The clist now contains two linear buffers c_quote and c_info, sized
36  * to c_cbmax.  The caller must hold a lock or token specific to the clist
37  * being manipulated.
38  */
39 #include <sys/param.h>
40 #include <sys/kernel.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/tty.h>
44 #include <sys/thread2.h>
45 
46 /*
47  * Allocate or reallocate clist buffers.
48  */
49 void
50 clist_alloc_cblocks(struct clist *cl, int ccmax)
51 {
52 	short *data;
53 	int count;
54 	int n;
55 
56 	if (ccmax == cl->c_ccmax)
57 		return;
58 	if (ccmax == 0) {
59 		clist_free_cblocks(cl);
60 		return;
61 	}
62 	data = kmalloc(ccmax * sizeof(*data), M_TTYS, M_INTWAIT|M_ZERO);
63 	/* NOTE: cl fields may now be different due to blocking */
64 
65 	count = cl->c_cc;
66 	if (cl->c_cc) {
67 		if (count > ccmax)
68 			count = ccmax;
69 		n = cl->c_ccmax - cl->c_cchead;
70 		if (n > count)
71 			n = count;
72 		bcopy(cl->c_data + cl->c_cchead, data, n * sizeof(*data));
73 		if (n < count) {
74 			bcopy(cl->c_data, data + n,
75 			      (count - n) * sizeof(*data));
76 		}
77 	}
78 	cl->c_cc = count;
79 	cl->c_ccmax = ccmax;
80 	cl->c_cchead = 0;
81 	cl->c_data = data;
82 }
83 
84 /*
85  * Free the clist's buffer.
86  */
87 void
88 clist_free_cblocks(struct clist *cl)
89 {
90 	short *data;
91 
92 	data = cl->c_data;
93 
94 	cl->c_cc = 0;
95 	cl->c_ccmax = 0;
96 	cl->c_cchead = 0;
97 	cl->c_unused01 = 0;
98 	cl->c_data = NULL;
99 	if (data)
100 		kfree(data, M_TTYS);
101 }
102 
103 /*
104  * Get a character from the head of a clist.
105  */
106 int
107 clist_getc(struct clist *cl)
108 {
109 	short c;
110 	int i;
111 
112 	if (cl->c_cc == 0)
113 		return -1;
114 	i = cl->c_cchead;
115 	c = cl->c_data[i];
116 	if (++i == cl->c_ccmax)
117 		i = 0;
118 	cl->c_cchead = i;
119 	--cl->c_cc;
120 	return ((int)c);
121 }
122 
123 /*
124  * Copy data from the clist to the destination linear buffer.
125  * Return the number of characters actually copied.
126  */
127 int
128 clist_qtob(struct clist *cl, char *dest, int n)
129 {
130 	int count;
131 	int i;
132 	short c;
133 
134 	if (n > cl->c_cc)
135 		n = cl->c_cc;
136 	count = n;
137 	i = cl->c_cchead;
138 
139 	while (n) {
140 		c = cl->c_data[i];
141 		if (++i == cl->c_ccmax)
142 			i = 0;
143 		*dest++ = (char)c;
144 		--n;
145 	}
146 	cl->c_cchead = i;
147 	cl->c_cc -= count;
148 
149 	return count;
150 }
151 
152 /*
153  * Flush characters from the head of the clist, deleting them.
154  */
155 void
156 ndflush(struct clist *cl, int n)
157 {
158 	int i;
159 
160 	if (n > cl->c_cc)
161 		n = cl->c_cc;
162 	i = cl->c_cchead + n;
163 	if (i >= cl->c_ccmax)
164 		i -= cl->c_ccmax;
165 	cl->c_cchead = i;
166 	cl->c_cc -= n;
167 }
168 
169 /*
170  * Append a character to the clist, return 0 on success, -1 if
171  * there is no room.  The character can be quoted by setting TTY_QUOTE.
172  */
173 int
174 clist_putc(int c, struct clist *cl)
175 {
176 	int i;
177 
178 	if (cl->c_cc == cl->c_ccmax)
179 		return -1;
180 	i = cl->c_cchead + cl->c_cc;
181 	if (i >= cl->c_ccmax)
182 		i -= cl->c_ccmax;
183 	cl->c_data[i] = (short)c & (TTY_QUOTE | TTY_CHARMASK);
184 	++cl->c_cc;
185 
186 	return 0;
187 }
188 
189 /*
190  * Copy data from linear buffer to clist chain.  Return the
191  * number of characters not copied.  The data will be flagged
192  * as not being quoted.
193  */
194 int
195 clist_btoq(char *src, int n, struct clist *cl)
196 {
197 	int i;
198 	int count;
199 	int remain;
200 
201 	count = cl->c_ccmax - cl->c_cc;		/* space available */
202 	if (count > n)
203 		count = n;			/* count = bytes to copy */
204 	remain = n - count;			/* remain = bytes not copied */
205 
206 	i = cl->c_cchead + cl->c_cc;		/* clist write index */
207 	if (i >= cl->c_ccmax)
208 		i -= cl->c_ccmax;
209 
210 	while (count) {
211 		cl->c_data[i] = (short)(uint8_t)*src;
212 		if (++i == cl->c_ccmax)
213 			i = 0;
214 		++src;
215 		--count;
216 	}
217 	cl->c_cc += n - remain;			/* bytes actually copied */
218 
219 	return remain;				/* return bytes not copied */
220 }
221 
222 /*
223  * Get the next character in the clist relative to cp.  If cp is NULL
224  * returns the first character in the clist.  The character is stored in
225  * *dst.  No clist pointers are advanced or adjusted.
226  *
227  * The returned pointer can be used as an iterator but should not be
228  * directly dereferenced.
229  */
230 void *
231 clist_nextc(struct clist *cl, void *cp, int *dst)
232 {
233 	int i;
234 
235 	if (cp == NULL) {
236 		if (cl->c_cc == 0) {
237 			*dst = -1;
238 			return NULL;
239 		}
240 		cp = &cl->c_data[cl->c_cchead];
241 		*dst = (uint16_t)*(short *)cp;	/* can be quoted */
242 		return cp;
243 	}
244 
245 	/*
246 	 * Use i to calculate the next logical index to determine if
247 	 * there are any characters remaining.
248 	 */
249 	i = (short *)cp - cl->c_data;
250 	if (i < cl->c_cchead)
251 		i += cl->c_ccmax - cl->c_cchead;
252 	else
253 		i -= cl->c_cchead;
254 	if (i + 1 == cl->c_cc) {		/* no more chars */
255 		*dst = 0;
256 		return NULL;
257 	}
258 
259 	/*
260 	 * We can just use cp to iterate the next actual buffer
261 	 * position.
262 	 */
263 	cp = (short *)cp + 1;			/* next char (use pointer) */
264 	if (cp == &cl->c_data[cl->c_ccmax])
265 		cp = &cl->c_data[0];
266 	*dst = (uint16_t)*(short *)cp;
267 
268 	return cp;
269 }
270 
271 /*
272  * "Unput" a character from a clist, returning it.
273  */
274 int
275 clist_unputc(struct clist *cl)
276 {
277 	int c;
278 	int i;
279 
280 	if (cl->c_cc == 0)
281 		return -1;
282 	--cl->c_cc;
283 	i = cl->c_cchead + cl->c_cc;
284 	if (i >= cl->c_ccmax)
285 		i -= cl->c_ccmax;
286 	c = (int)(uint16_t)cl->c_data[i];
287 
288 	return c;
289 }
290 
291 /*
292  * Move characters in source clist to destination clist,
293  * preserving quote bits.  Non-critical path.
294  */
295 void
296 clist_catq(struct clist *cls, struct clist *cld)
297 {
298 	int c;
299 
300 	while ((c = clist_getc(cls)) != -1)
301 		clist_putc(c, cld);
302 }
303