Fork me on GitHub

root/drivers/char/tty_queue.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_free_cblock
  2. put_free_cblock
  3. insert_cblock_in_head
  4. insert_cblock_in_tail
  5. delete_cblock_from_head
  6. delete_cblock_from_tail
  7. tty_queue_putchar
  8. tty_queue_unputchar
  9. tty_queue_getchar
  10. tty_queue_flush
  11. tty_queue_room
  12. tty_queue_init

   1 /*
   2  * fiwix/drivers/char/tty_queue.c
   3  *
   4  * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/asm.h>
   9 #include <fiwix/kernel.h>
  10 #include <fiwix/tty.h>
  11 #include <fiwix/errno.h>
  12 #include <fiwix/string.h>
  13 
  14 /*
  15  * tty_queue.c implements a queue using a static-sized doubly linked list of a
  16  * central pool of buffers which covers all ttys.
  17  *
  18  *  head                                     tail
  19  * +--------------+  +--------------+  ...  +--------------+
  20  * |prev|data|next|  |prev|data|next|  ...  |prev|data|next|
  21  * | /  |    |  -->  <--  |    |  -->  ...  <--  |    |  / |
  22  * +--------------+  +--------------+  ...  +--------------+
  23  *  (cblock)          (cblock)               (cblock)
  24  */
  25 
  26 struct cblock cblock_pool[CB_POOL_SIZE];
  27 struct cblock *cblock_pool_head;
  28 
  29 static struct cblock *get_free_cblock(void)
  30 {
  31         struct cblock *new = NULL;
  32 
  33         if(cblock_pool_head) {
  34                 new = cblock_pool_head;
  35                 cblock_pool_head = cblock_pool_head->next;
  36                 new->prev = new->next = NULL;
  37         }
  38         return new;
  39 }
  40 
  41 static void put_free_cblock(struct cblock *old)
  42 {
  43         old->prev = NULL;
  44         old->next = cblock_pool_head;
  45         cblock_pool_head = old;
  46 }
  47 
  48 static struct cblock *insert_cblock_in_head(struct clist *q)
  49 {
  50         struct cblock *cb;
  51 
  52         if(q->cb_num >= NR_CB_QUEUE) {
  53                 return NULL;
  54         }
  55         if(!(cb = get_free_cblock())) {
  56                 return NULL;
  57         }
  58 
  59         /* initialize cblock */
  60         cb->start_off = cb->end_off = 0;
  61         memset_b(cb->data, 0, CBSIZE);
  62         cb->prev = cb->next = NULL;
  63         q->cb_num++;
  64 
  65         if(!q->head) {
  66                 q->head = q->tail = cb;
  67         } else {
  68                 cb->prev = NULL;
  69                 cb->next = q->head;
  70                 q->head->prev = cb;
  71                 q->head = cb;
  72         }
  73         return cb;
  74 }
  75 
  76 static struct cblock *insert_cblock_in_tail(struct clist *q)
  77 {
  78         struct cblock *cb;
  79 
  80         if(q->cb_num >= NR_CB_QUEUE) {
  81                 return NULL;
  82         }
  83         if(!(cb = get_free_cblock())) {
  84                 return NULL;
  85         }
  86 
  87         /* initialize cblock */
  88         cb->start_off = cb->end_off = 0;
  89         memset_b(cb->data, 0, CBSIZE);
  90         cb->prev = cb->next = NULL;
  91         q->cb_num++;
  92 
  93         if(!q->tail) {
  94                 q->head = q->tail = cb;
  95         } else {
  96                 cb->prev = q->tail;
  97                 cb->next = NULL;
  98                 q->tail->next = cb;
  99                 q->tail = cb;
 100         }
 101         return cb;
 102 }
 103 
 104 static void delete_cblock_from_head(struct clist *q)
 105 {
 106         struct cblock *tmp;
 107 
 108         if(!q->head) {
 109                 return;
 110         }
 111 
 112         tmp = q->head;
 113         if(q->head == q->tail) {
 114                 q->head = q->tail = NULL;
 115         } else {
 116                 q->head = q->head->next;
 117                 q->head->prev = NULL;
 118         }
 119 
 120         q->count -= tmp->end_off - tmp->start_off;
 121         q->cb_num--;
 122         put_free_cblock(tmp);
 123 }
 124 
 125 static void delete_cblock_from_tail(struct clist *q)
 126 {
 127         struct cblock *tmp;
 128 
 129         if(!q->tail) {
 130                 return;
 131         }
 132 
 133         tmp = q->tail;
 134         if(q->head == q->tail) {
 135                 q->head = q->tail = NULL;
 136         } else {
 137                 q->tail = q->tail->prev;
 138                 q->tail->next = NULL;
 139         }
 140 
 141         q->count -= tmp->end_off - tmp->start_off;
 142         q->cb_num--;
 143         put_free_cblock(tmp);
 144 }
 145 
 146 int tty_queue_putchar(struct tty *tty, struct clist *q, unsigned char ch)
 147 {
 148         unsigned long int flags;
 149         struct cblock *cb;
 150         int errno;
 151 
 152         SAVE_FLAGS(flags); CLI();
 153 
 154         cb = q->tail;
 155         if(!cb) {
 156                 cb = insert_cblock_in_tail(q);
 157                 if(!cb) {
 158                         RESTORE_FLAGS(flags);
 159                         return -EAGAIN;
 160                 }
 161         }
 162 
 163         if(cb->end_off < CBSIZE) {
 164                 cb->data[cb->end_off] = ch;
 165                 cb->end_off++;
 166                 q->count++;
 167                 errno = 0;
 168         } else if(insert_cblock_in_tail(q)) {
 169                 tty_queue_putchar(tty, q, ch);
 170                 errno = 0;
 171         } else {
 172                 errno = -EAGAIN;
 173         }
 174 
 175         RESTORE_FLAGS(flags);
 176         return errno;
 177 }
 178 
 179 int tty_queue_unputchar(struct clist *q)
 180 {
 181         unsigned long int flags;
 182         struct cblock *cb;
 183         unsigned char ch;
 184 
 185         SAVE_FLAGS(flags); CLI();
 186 
 187         ch = 0;
 188         cb = q->tail;
 189         if(cb) {
 190                 if(cb->end_off > cb->start_off) {
 191                         ch = cb->data[cb->end_off - 1];
 192                         cb->end_off--;
 193                         q->count--;
 194                 }
 195                 if(cb->end_off - cb->start_off == 0) {
 196                         delete_cblock_from_tail(q);
 197                 }
 198         }
 199 
 200         RESTORE_FLAGS(flags);
 201         return ch;
 202 }
 203 
 204 unsigned char tty_queue_getchar(struct clist *q)
 205 {
 206         unsigned long int flags;
 207         struct cblock *cb;
 208         unsigned char ch;
 209 
 210         SAVE_FLAGS(flags); CLI();
 211 
 212         ch = 0;
 213         cb = q->head;
 214         if(cb) {
 215                 if(cb->start_off < cb->end_off) {
 216                         ch = cb->data[cb->start_off];
 217                         cb->start_off++;
 218                         q->count--;
 219                 }
 220                 if(cb->end_off - cb->start_off == 0) {
 221                         delete_cblock_from_head(q);
 222                 }
 223         }
 224 
 225         RESTORE_FLAGS(flags);
 226         return ch;
 227 }
 228 
 229 void tty_queue_flush(struct clist *q)
 230 {
 231         unsigned long int flags;
 232 
 233         SAVE_FLAGS(flags); CLI();
 234 
 235         while(q->head != NULL) {
 236                 delete_cblock_from_head(q);
 237         }
 238 
 239         RESTORE_FLAGS(flags);
 240 }
 241 
 242 int tty_queue_room(struct clist *q)
 243 {
 244         return (NR_CB_QUEUE * CBSIZE) - q->count;
 245 }
 246 
 247 void tty_queue_init(void)
 248 {
 249         int n;
 250         struct cblock *cb;
 251 
 252         memset_b(cblock_pool, NULL, sizeof(cblock_pool));
 253 
 254         /* cblock free list initialization */
 255         cblock_pool_head = NULL;
 256         n = CB_POOL_SIZE;
 257         while(n--) {
 258                 cb = &cblock_pool[n];
 259                 put_free_cblock(cb);
 260         }
 261 }

/* [previous][next][first][last][top][bottom][index][help] */