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 45 /* 46 * Allocate or reallocate clist buffers. 47 */ 48 void 49 clist_alloc_cblocks(struct clist *cl, int ccmax) 50 { 51 short *data; 52 int count; 53 int n; 54 55 if (ccmax == cl->c_ccmax) 56 return; 57 if (ccmax == 0) { 58 clist_free_cblocks(cl); 59 return; 60 } 61 data = kmalloc(ccmax * sizeof(*data), M_TTYS, M_INTWAIT|M_ZERO); 62 /* NOTE: cl fields may now be different due to blocking */ 63 64 count = cl->c_cc; 65 if (cl->c_cc) { 66 if (count > ccmax) 67 count = ccmax; 68 n = cl->c_ccmax - cl->c_cchead; 69 if (n > count) 70 n = count; 71 bcopy(cl->c_data + cl->c_cchead, data, n * sizeof(*data)); 72 if (n < count) { 73 bcopy(cl->c_data, data + n, 74 (count - n) * sizeof(*data)); 75 } 76 } 77 cl->c_cc = count; 78 cl->c_ccmax = ccmax; 79 cl->c_cchead = 0; 80 cl->c_data = data; 81 } 82 83 /* 84 * Free the clist's buffer. 85 */ 86 void 87 clist_free_cblocks(struct clist *cl) 88 { 89 short *data; 90 91 data = cl->c_data; 92 93 cl->c_cc = 0; 94 cl->c_ccmax = 0; 95 cl->c_cchead = 0; 96 cl->c_unused01 = 0; 97 cl->c_data = NULL; 98 if (data) 99 kfree(data, M_TTYS); 100 } 101 102 /* 103 * Get a character from the head of a clist. 104 */ 105 int 106 clist_getc(struct clist *cl) 107 { 108 short c; 109 int i; 110 111 if (cl->c_cc == 0) 112 return -1; 113 i = cl->c_cchead; 114 c = cl->c_data[i]; 115 if (++i == cl->c_ccmax) 116 i = 0; 117 cl->c_cchead = i; 118 --cl->c_cc; 119 return ((int)c); 120 } 121 122 /* 123 * Copy data from the clist to the destination linear buffer. 124 * Return the number of characters actually copied. 125 */ 126 int 127 clist_qtob(struct clist *cl, char *dest, int n) 128 { 129 int count; 130 int i; 131 short c; 132 133 if (n > cl->c_cc) 134 n = cl->c_cc; 135 count = n; 136 i = cl->c_cchead; 137 138 while (n) { 139 c = cl->c_data[i]; 140 if (++i == cl->c_ccmax) 141 i = 0; 142 *dest++ = (char)c; 143 --n; 144 } 145 cl->c_cchead = i; 146 cl->c_cc -= count; 147 148 return count; 149 } 150 151 /* 152 * Flush characters from the head of the clist, deleting them. 153 */ 154 void 155 ndflush(struct clist *cl, int n) 156 { 157 int i; 158 159 if (n > cl->c_cc) 160 n = cl->c_cc; 161 i = cl->c_cchead + n; 162 if (i >= cl->c_ccmax) 163 i -= cl->c_ccmax; 164 cl->c_cchead = i; 165 cl->c_cc -= n; 166 } 167 168 /* 169 * Append a character to the clist, return 0 on success, -1 if 170 * there is no room. The character can be quoted by setting TTY_QUOTE. 171 */ 172 int 173 clist_putc(int c, struct clist *cl) 174 { 175 int i; 176 177 if (cl->c_cc == cl->c_ccmax) 178 return -1; 179 i = cl->c_cchead + cl->c_cc; 180 if (i >= cl->c_ccmax) 181 i -= cl->c_ccmax; 182 cl->c_data[i] = (short)c & (TTY_QUOTE | TTY_CHARMASK); 183 ++cl->c_cc; 184 185 return 0; 186 } 187 188 /* 189 * Copy data from linear buffer to clist chain. Return the 190 * number of characters not copied. The data will be flagged 191 * as not being quoted. 192 */ 193 int 194 clist_btoq(char *src, int n, struct clist *cl) 195 { 196 int i; 197 int count; 198 int remain; 199 200 count = cl->c_ccmax - cl->c_cc; /* space available */ 201 if (count > n) 202 count = n; /* count = bytes to copy */ 203 remain = n - count; /* remain = bytes not copied */ 204 205 i = cl->c_cchead + cl->c_cc; /* clist write index */ 206 if (i >= cl->c_ccmax) 207 i -= cl->c_ccmax; 208 209 while (count) { 210 cl->c_data[i] = (short)(uint8_t)*src; 211 if (++i == cl->c_ccmax) 212 i = 0; 213 ++src; 214 --count; 215 } 216 cl->c_cc += n - remain; /* bytes actually copied */ 217 218 return remain; /* return bytes not copied */ 219 } 220 221 /* 222 * Get the next character in the clist relative to cp. If cp is NULL 223 * returns the first character in the clist. The character is stored in 224 * *dst. No clist pointers are advanced or adjusted. 225 * 226 * The returned pointer can be used as an iterator but should not be 227 * directly dereferenced. 228 */ 229 void * 230 clist_nextc(struct clist *cl, void *cp, int *dst) 231 { 232 int i; 233 234 if (cp == NULL) { 235 if (cl->c_cc == 0) { 236 *dst = -1; 237 return NULL; 238 } 239 cp = &cl->c_data[cl->c_cchead]; 240 *dst = (uint16_t)*(short *)cp; /* can be quoted */ 241 return cp; 242 } 243 244 /* 245 * Use i to calculate the next logical index to determine if 246 * there are any characters remaining. 247 */ 248 i = (short *)cp - cl->c_data; 249 if (i < cl->c_cchead) 250 i += cl->c_ccmax - cl->c_cchead; 251 else 252 i -= cl->c_cchead; 253 if (i + 1 == cl->c_cc) { /* no more chars */ 254 *dst = 0; 255 return NULL; 256 } 257 258 /* 259 * We can just use cp to iterate the next actual buffer 260 * position. 261 */ 262 cp = (short *)cp + 1; /* next char (use pointer) */ 263 if (cp == &cl->c_data[cl->c_ccmax]) 264 cp = &cl->c_data[0]; 265 *dst = (uint16_t)*(short *)cp; 266 267 return cp; 268 } 269 270 /* 271 * "Unput" a character from a clist, returning it. 272 */ 273 int 274 clist_unputc(struct clist *cl) 275 { 276 int c; 277 int i; 278 279 if (cl->c_cc == 0) 280 return -1; 281 --cl->c_cc; 282 i = cl->c_cchead + cl->c_cc; 283 if (i >= cl->c_ccmax) 284 i -= cl->c_ccmax; 285 c = (int)(uint16_t)cl->c_data[i]; 286 287 return c; 288 } 289 290 /* 291 * Move characters in source clist to destination clist, 292 * preserving quote bits. Non-critical path. 293 */ 294 void 295 clist_catq(struct clist *cls, struct clist *cld) 296 { 297 int c; 298 299 while ((c = clist_getc(cls)) != -1) 300 clist_putc(c, cld); 301 } 302