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