--- patch/linux +++ patch/linux @@ -2123,7 +2123,7 @@ diff -urN a/drivers/char/cocd.c b/drivers/char/cocd.c --- a/drivers/char/cocd.c +++ b/drivers/char/cocd.c -@@ -0,0 +1,296 @@ +@@ -0,0 +1,349 @@ +/* + * Copyright (C) 2004 Dan Aloni + * @@ -2133,6 +2133,10 @@ + * Also based on The tiny_tty.c example driver by Greg Kroah-Hartman (greg@kroah.com). + */ + ++/* 20040908: Ballard, Jonathan H. ++ * : Implemented cocd_task() & throttle ++*/ ++ +#include +#include +#include @@ -2146,6 +2150,7 @@ +#include +#include + ++#include +#include +#include +#include @@ -2158,11 +2159,15 @@ + struct tty_struct *tty; /* pointer to the tty for this device */ + struct semaphore sem; /* locks this structure */ + int open_count; /* number of times this port has been opened */ ++ int throttled; +}; + +static struct tty_driver *cocd_driver = NULL; ++static struct work_struct cocd_work; +DECLARE_MUTEX(cocd_sem); + ++ ++ +int cocd_open(struct tty_struct *tty, struct file * filp) +{ + struct cocd_tty *cocd = NULL; @@ -2184,6 +2188,7 @@ + init_MUTEX_LOCKED(&cocd->sem); + cocd->open_count = 0; + cocd->tty = tty; ++ cocd->throttled = 0; + tty->driver_data = cocd; + } else { + down (&cocd->sem); @@ -2225,50 +2226,71 @@ + up(&cocd_sem); +} + -+void cocd_interrupt(void) ++static void cocd_task(void *data) +{ -+ co_message_node_t *node_message; ++ static co_message_node_t *current_message; ++ static unsigned current_message_index; ++ struct cocd_tty *cocd; ++ struct tty_struct *tty; ++ co_linux_message_t *message; ++ char *p, *e; + -+ if (!cocd_driver) -+ return; ++ if(!current_message) { ++ if(!co_get_message(¤t_message, CO_DEVICE_SERIAL)) { ++ current_message = 0; ++ return; ++ } ++ if(!current_message) ++ return; ++ } + -+ while (co_get_message(&node_message, CO_DEVICE_SERIAL)) { -+ struct tty_struct *tty = NULL; -+ struct cocd_tty *cocd = NULL; -+ unsigned long i; -+ co_linux_message_t *message; -+ -+ message = (co_linux_message_t *)&node_message->msg.data; -+ -+ if (message->unit >= CO_MODULE_MAX_SERIAL) -+ goto next; ++ message = (co_linux_message_t *)¤t_message->msg.data; ++ if (message->unit >= CO_MODULE_MAX_SERIAL) ++ return; + -+ tty = cocd_driver->ttys[message->unit]; -+ if (!tty) -+ goto next; ++ tty = cocd_driver->ttys[message->unit]; ++ if (!tty) ++ return; + -+ cocd = (struct cocd_tty *)tty->driver_data; -+ if (!cocd) -+ goto next; -+ -+ down(&cocd->sem); ++ cocd = (struct cocd_tty *)tty->driver_data; ++ if (!cocd) ++ return; ++ down(&cocd->sem); ++ if(cocd->throttled) { ++ up(&cocd->sem); ++ return; ++ } ++ up(&cocd->sem); + -+ for (i=0; i < message->size; i++) { -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) -+ tty_flip_buffer_push(tty); -+ -+ tty_insert_flip_char(tty, message->data[i], 0); -+ } -+ ++ p = message->data + current_message_index; ++ e = message->data + message->size; ++ while(p < e && tty->flip.count < TTY_FLIPBUF_SIZE) ++ tty_insert_flip_char(tty, *(p++), 0); ++ if(p < e) { ++ current_message_index = (unsigned)(p - message->data); + tty_flip_buffer_push(tty); -+ -+ up(&cocd->sem); -+ -+ next: -+ co_free_message(node_message); ++ schedule_work(&cocd_work); ++ return; ++ } ++ co_free_message(current_message); ++ current_message_index = 0; ++ if(!co_get_message(¤t_message, CO_DEVICE_SERIAL)) ++ current_message = 0; ++ if(current_message) ++ schedule_work(&cocd_work); ++ else { ++ if(tty->flip.count) ++ tty_flip_buffer_push(tty); + } +} + ++void cocd_interrupt(void) ++{ ++ if (!cocd_driver) ++ return; ++ schedule_work(&cocd_work); ++} ++ +int cocd_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ @@ -2299,7 +2320,7 @@ + co_send_message(CO_MODULE_LINUX, + CO_MODULE_SERIAL0 + tty->index, + CO_PRIORITY_DISCARDABLE, -+ CO_MESSAGE_TYPE_OTHER, ++ CO_MESSAGE_TYPE_STRING, + count_partial, + kbuf_scan); + @@ -2336,8 +2336,27 @@ +{ +} + ++void cocd_throttle(struct tty_struct * tty) ++{ ++ struct cocd_tty *cocd; ++ cocd = (struct cocd_tty *)tty->driver_data; ++ if (!cocd) ++ return; ++ down(&cocd->sem); ++ cocd->throttled = 1; ++ up(&cocd->sem); ++} ++ +void cocd_unthrottle(struct tty_struct * tty) +{ ++ struct cocd_tty *cocd; ++ cocd = (struct cocd_tty *)tty->driver_data; ++ if (!cocd) ++ return; ++ down(&cocd->sem); ++ cocd->throttled = 0; ++ up(&cocd->sem); ++ schedule_work(&cocd_work); +} + +void cocd_flush_buffer(struct tty_struct *tty) @@ -2359,6 +2378,7 @@ + .write = cocd_write, + .write_room = cocd_write_room, + .flush_buffer = cocd_flush_buffer, ++ .throttle = cocd_throttle, + .unthrottle = cocd_unthrottle, + .hangup = cocd_hangup, + .chars_in_buffer = cocd_chars_in_buffer, @@ -2407,7 +2408,7 @@ + cocd_driver->type = TTY_DRIVER_TYPE_SERIAL; + cocd_driver->subtype = 0; + cocd_driver->init_termios = tty_std_termios; -+ cocd_driver->flags = TTY_DRIVER_REAL_RAW; ++ cocd_driver->flags = 0; + + tty_set_operations(cocd_driver, &cocd_ops); + @@ -2416,6 +2416,8 @@ + + register_console(&cocd_cons); + ++ INIT_WORK(&cocd_work, cocd_task, 0); ++ + return 0; +} +