aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r--drivers/char/tty_io.c266
1 files changed, 234 insertions, 32 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 4b1eef51ec59..1eda82b31a61 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -166,9 +166,12 @@ static struct tty_struct *alloc_tty_struct(void)
166 return tty; 166 return tty;
167} 167}
168 168
169static void tty_buffer_free_all(struct tty_struct *);
170
169static inline void free_tty_struct(struct tty_struct *tty) 171static inline void free_tty_struct(struct tty_struct *tty)
170{ 172{
171 kfree(tty->write_buf); 173 kfree(tty->write_buf);
174 tty_buffer_free_all(tty);
172 kfree(tty); 175 kfree(tty);
173} 176}
174 177
@@ -231,6 +234,201 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
231} 234}
232 235
233/* 236/*
237 * Tty buffer allocation management
238 */
239
240static void tty_buffer_free_all(struct tty_struct *tty)
241{
242 struct tty_buffer *thead;
243 while((thead = tty->buf.head) != NULL) {
244 tty->buf.head = thead->next;
245 kfree(thead);
246 }
247 while((thead = tty->buf.free) != NULL) {
248 tty->buf.free = thead->next;
249 kfree(thead);
250 }
251 tty->buf.tail = NULL;
252}
253
254static void tty_buffer_init(struct tty_struct *tty)
255{
256 tty->buf.head = NULL;
257 tty->buf.tail = NULL;
258 tty->buf.free = NULL;
259}
260
261static struct tty_buffer *tty_buffer_alloc(size_t size)
262{
263 struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
264 if(p == NULL)
265 return NULL;
266 p->used = 0;
267 p->size = size;
268 p->next = NULL;
269 p->char_buf_ptr = (char *)(p->data);
270 p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
271/* printk("Flip create %p\n", p); */
272 return p;
273}
274
275/* Must be called with the tty_read lock held. This needs to acquire strategy
276 code to decide if we should kfree or relink a given expired buffer */
277
278static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
279{
280 /* Dumb strategy for now - should keep some stats */
281/* printk("Flip dispose %p\n", b); */
282 if(b->size >= 512)
283 kfree(b);
284 else {
285 b->next = tty->buf.free;
286 tty->buf.free = b;
287 }
288}
289
290static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
291{
292 struct tty_buffer **tbh = &tty->buf.free;
293 while((*tbh) != NULL) {
294 struct tty_buffer *t = *tbh;
295 if(t->size >= size) {
296 *tbh = t->next;
297 t->next = NULL;
298 t->used = 0;
299 /* DEBUG ONLY */
300 memset(t->data, '*', size);
301/* printk("Flip recycle %p\n", t); */
302 return t;
303 }
304 tbh = &((*tbh)->next);
305 }
306 /* Round the buffer size out */
307 size = (size + 0xFF) & ~ 0xFF;
308 return tty_buffer_alloc(size);
309 /* Should possibly check if this fails for the largest buffer we
310 have queued and recycle that ? */
311}
312
313int tty_buffer_request_room(struct tty_struct *tty, size_t size)
314{
315 struct tty_buffer *b = tty->buf.head, *n;
316 int left = 0;
317
318 /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
319 remove this conditional if its worth it. This would be invisible
320 to the callers */
321 if(b != NULL)
322 left = b->size - b->used;
323 if(left >= size)
324 return size;
325 /* This is the slow path - looking for new buffers to use */
326 n = tty_buffer_find(tty, size);
327 if(n == NULL)
328 return left;
329 n->next = b;
330 if(b != NULL)
331 b->next = n;
332 else
333 tty->buf.head = n;
334 tty->buf.tail = n;
335 return size;
336}
337
338EXPORT_SYMBOL_GPL(tty_buffer_request_room);
339
340int tty_insert_flip_string(struct tty_struct *tty, unsigned char *chars, size_t size)
341{
342 int copied = 0;
343 do {
344 int space = tty_buffer_request_room(tty, size - copied);
345 struct tty_buffer *tb = tty->buf.tail;
346 /* If there is no space then tb may be NULL */
347 if(unlikely(space == 0))
348 break;
349 memcpy(tb->char_buf_ptr + tb->used, chars, space);
350 memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
351 tb->used += space;
352 copied += space;
353 chars += space;
354/* printk("Flip insert %d.\n", space); */
355 }
356 /* There is a small chance that we need to split the data over
357 several buffers. If this is the case we must loop */
358 while (unlikely(size > copied));
359 return copied;
360}
361
362EXPORT_SYMBOL_GPL(tty_insert_flip_string);
363
364int tty_insert_flip_string_flags(struct tty_struct *tty, unsigned char *chars, char *flags, size_t size)
365{
366 int copied = 0;
367 do {
368 int space = tty_buffer_request_room(tty, size - copied);
369 struct tty_buffer *tb = tty->buf.tail;
370 /* If there is no space then tb may be NULL */
371 if(unlikely(space == 0))
372 break;
373 memcpy(tb->char_buf_ptr + tb->used, chars, space);
374 memcpy(tb->flag_buf_ptr + tb->used, flags, space);
375 tb->used += space;
376 copied += space;
377 chars += space;
378 flags += space;
379 }
380 /* There is a small chance that we need to split the data over
381 several buffers. If this is the case we must loop */
382 while (unlikely(size > copied));
383 return copied;
384}
385
386EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags);
387
388
389/*
390 * Prepare a block of space in the buffer for data. Returns the length
391 * available and buffer pointer to the space which is now allocated and
392 * accounted for as ready for normal characters. This is used for drivers
393 * that need their own block copy routines into the buffer. There is no
394 * guarantee the buffer is a DMA target!
395 */
396
397int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size)
398{
399 int space = tty_buffer_request_room(tty, size);
400 struct tty_buffer *tb = tty->buf.tail;
401 *chars = tb->char_buf_ptr + tb->used;
402 memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
403 tb->used += space;
404 return space;
405}
406
407EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
408
409/*
410 * Prepare a block of space in the buffer for data. Returns the length
411 * available and buffer pointer to the space which is now allocated and
412 * accounted for as ready for characters. This is used for drivers
413 * that need their own block copy routines into the buffer. There is no
414 * guarantee the buffer is a DMA target!
415 */
416
417int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size)
418{
419 int space = tty_buffer_request_room(tty, size);
420 struct tty_buffer *tb = tty->buf.tail;
421 *chars = tb->char_buf_ptr + tb->used;
422 *flags = tb->flag_buf_ptr + tb->used;
423 tb->used += space;
424 return space;
425}
426
427EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
428
429
430
431/*
234 * This is probably overkill for real world processors but 432 * This is probably overkill for real world processors but
235 * they are not on hot paths so a little discipline won't do 433 * they are not on hot paths so a little discipline won't do
236 * any harm. 434 * any harm.
@@ -492,6 +690,17 @@ restart:
492 if (ld == NULL) 690 if (ld == NULL)
493 return -EINVAL; 691 return -EINVAL;
494 692
693 /*
694 * No more input please, we are switching. The new ldisc
695 * will update this value in the ldisc open function
696 */
697
698 tty->receive_room = 0;
699
700 /*
701 * Problem: What do we do if this blocks ?
702 */
703
495 tty_wait_until_sent(tty, 0); 704 tty_wait_until_sent(tty, 0);
496 705
497 if (tty->ldisc.num == ldisc) { 706 if (tty->ldisc.num == ldisc) {
@@ -560,9 +769,9 @@ restart:
560 * we say so later on. 769 * we say so later on.
561 */ 770 */
562 771
563 work = cancel_delayed_work(&tty->flip.work); 772 work = cancel_delayed_work(&tty->buf.work);
564 /* 773 /*
565 * Wait for ->hangup_work and ->flip.work handlers to terminate 774 * Wait for ->hangup_work and ->buf.work handlers to terminate
566 */ 775 */
567 776
568 flush_scheduled_work(); 777 flush_scheduled_work();
@@ -616,7 +825,7 @@ restart:
616 /* Restart it in case no characters kick it off. Safe if 825 /* Restart it in case no characters kick it off. Safe if
617 already running */ 826 already running */
618 if (work) 827 if (work)
619 schedule_delayed_work(&tty->flip.work, 1); 828 schedule_delayed_work(&tty->buf.work, 1);
620 return retval; 829 return retval;
621} 830}
622 831
@@ -1721,10 +1930,10 @@ static void release_dev(struct file * filp)
1721 */ 1930 */
1722 clear_bit(TTY_LDISC, &tty->flags); 1931 clear_bit(TTY_LDISC, &tty->flags);
1723 clear_bit(TTY_DONT_FLIP, &tty->flags); 1932 clear_bit(TTY_DONT_FLIP, &tty->flags);
1724 cancel_delayed_work(&tty->flip.work); 1933 cancel_delayed_work(&tty->buf.work);
1725 1934
1726 /* 1935 /*
1727 * Wait for ->hangup_work and ->flip.work handlers to terminate 1936 * Wait for ->hangup_work and ->buf.work handlers to terminate
1728 */ 1937 */
1729 1938
1730 flush_scheduled_work(); 1939 flush_scheduled_work();
@@ -2518,17 +2727,15 @@ EXPORT_SYMBOL(do_SAK);
2518 2727
2519/* 2728/*
2520 * This routine is called out of the software interrupt to flush data 2729 * This routine is called out of the software interrupt to flush data
2521 * from the flip buffer to the line discipline. 2730 * from the buffer chain to the line discipline.
2522 */ 2731 */
2523 2732
2524static void flush_to_ldisc(void *private_) 2733static void flush_to_ldisc(void *private_)
2525{ 2734{
2526 struct tty_struct *tty = (struct tty_struct *) private_; 2735 struct tty_struct *tty = (struct tty_struct *) private_;
2527 unsigned char *cp;
2528 char *fp;
2529 int count;
2530 unsigned long flags; 2736 unsigned long flags;
2531 struct tty_ldisc *disc; 2737 struct tty_ldisc *disc;
2738 struct tty_buffer *tbuf;
2532 2739
2533 disc = tty_ldisc_ref(tty); 2740 disc = tty_ldisc_ref(tty);
2534 if (disc == NULL) /* !TTY_LDISC */ 2741 if (disc == NULL) /* !TTY_LDISC */
@@ -2538,28 +2745,22 @@ static void flush_to_ldisc(void *private_)
2538 /* 2745 /*
2539 * Do it after the next timer tick: 2746 * Do it after the next timer tick:
2540 */ 2747 */
2541 schedule_delayed_work(&tty->flip.work, 1); 2748 schedule_delayed_work(&tty->buf.work, 1);
2542 goto out; 2749 goto out;
2543 } 2750 }
2544 spin_lock_irqsave(&tty->read_lock, flags); 2751 spin_lock_irqsave(&tty->read_lock, flags);
2545 if (tty->flip.buf_num) { 2752 while((tbuf = tty->buf.head) != NULL) {
2546 cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; 2753 tty->buf.head = tbuf->next;
2547 fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; 2754 spin_unlock_irqrestore(&tty->read_lock, flags);
2548 tty->flip.buf_num = 0; 2755 /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */
2549 tty->flip.char_buf_ptr = tty->flip.char_buf; 2756 disc->receive_buf(tty, tbuf->char_buf_ptr,
2550 tty->flip.flag_buf_ptr = tty->flip.flag_buf; 2757 tbuf->flag_buf_ptr,
2551 } else { 2758 tbuf->used);
2552 cp = tty->flip.char_buf; 2759 spin_lock_irqsave(&tty->read_lock, flags);
2553 fp = tty->flip.flag_buf; 2760 tty_buffer_free(tty, tbuf);
2554 tty->flip.buf_num = 1; 2761 }
2555 tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE; 2762 tty->buf.tail = NULL;
2556 tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
2557 }
2558 count = tty->flip.count;
2559 tty->flip.count = 0;
2560 spin_unlock_irqrestore(&tty->read_lock, flags); 2763 spin_unlock_irqrestore(&tty->read_lock, flags);
2561
2562 disc->receive_buf(tty, cp, fp, count);
2563out: 2764out:
2564 tty_ldisc_deref(disc); 2765 tty_ldisc_deref(disc);
2565} 2766}
@@ -2654,11 +2855,12 @@ void tty_flip_buffer_push(struct tty_struct *tty)
2654 if (tty->low_latency) 2855 if (tty->low_latency)
2655 flush_to_ldisc((void *) tty); 2856 flush_to_ldisc((void *) tty);
2656 else 2857 else
2657 schedule_delayed_work(&tty->flip.work, 1); 2858 schedule_delayed_work(&tty->buf.work, 1);
2658} 2859}
2659 2860
2660EXPORT_SYMBOL(tty_flip_buffer_push); 2861EXPORT_SYMBOL(tty_flip_buffer_push);
2661 2862
2863
2662/* 2864/*
2663 * This subroutine initializes a tty structure. 2865 * This subroutine initializes a tty structure.
2664 */ 2866 */
@@ -2669,10 +2871,10 @@ static void initialize_tty_struct(struct tty_struct *tty)
2669 tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); 2871 tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
2670 tty->pgrp = -1; 2872 tty->pgrp = -1;
2671 tty->overrun_time = jiffies; 2873 tty->overrun_time = jiffies;
2672 tty->flip.char_buf_ptr = tty->flip.char_buf; 2874 tty->buf.head = tty->buf.tail = NULL;
2673 tty->flip.flag_buf_ptr = tty->flip.flag_buf; 2875 tty_buffer_init(tty);
2674 INIT_WORK(&tty->flip.work, flush_to_ldisc, tty); 2876 INIT_WORK(&tty->buf.work, flush_to_ldisc, tty);
2675 init_MUTEX(&tty->flip.pty_sem); 2877 init_MUTEX(&tty->buf.pty_sem);
2676 init_MUTEX(&tty->termios_sem); 2878 init_MUTEX(&tty->termios_sem);
2677 init_waitqueue_head(&tty->write_wait); 2879 init_waitqueue_head(&tty->write_wait);
2678 init_waitqueue_head(&tty->read_wait); 2880 init_waitqueue_head(&tty->read_wait);