diff options
author | Martin Dietze <di@fh-wedel.de> | 2006-09-08 12:41:48 +0000 |
---|---|---|
committer | Martin Dietze <di@fh-wedel.de> | 2006-09-08 12:41:48 +0000 |
commit | 03b3579813b72ea73f9961105c598581e3f073e0 (patch) | |
tree | d58b298506103cc591fb4fd1c51bea9f88ee3f61 /packages/linux/linux-mtx-2-2.4.27/45-acm-tty.patch | |
parent | 6f4455ad4fe9f67a9b2cc316663b69f085af4031 (diff) |
linux kernels: updated kernels plus patches for nylon/mtx
* linux-mtx-1-2.4.27: the standard kernel used for the 4G access cube
* linux-mtx-1u-2.4.27: the customized kernel for the 4G Surfbox I
* linux-mtx-2-2.4.27: the customized kernel for the 4G Surfbox II
Diffstat (limited to 'packages/linux/linux-mtx-2-2.4.27/45-acm-tty.patch')
-rw-r--r-- | packages/linux/linux-mtx-2-2.4.27/45-acm-tty.patch | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/packages/linux/linux-mtx-2-2.4.27/45-acm-tty.patch b/packages/linux/linux-mtx-2-2.4.27/45-acm-tty.patch new file mode 100644 index 0000000000..028d10ad9a --- /dev/null +++ b/packages/linux/linux-mtx-2-2.4.27/45-acm-tty.patch @@ -0,0 +1,252 @@ +--- linux/drivers/usb/acm.c~45-acm-tty.patch 2006-06-07 11:21:21.648422000 +0200 ++++ linux/drivers/usb/acm.c 2006-06-09 17:20:51.735793750 +0200 +@@ -139,6 +139,8 @@ + * Internal driver structures. + */ + ++#define TD_SIZE 16384 ++ + struct acm { + struct usb_device *dev; /* the coresponding usb device */ + struct usb_interface *iface; /* the interfaces - +0 control +1 data */ +@@ -153,6 +155,11 @@ + unsigned int minor; /* acm minor number */ + unsigned char throttle; /* throttled by tty layer */ + unsigned char clocal; /* termios CLOCAL */ ++ unsigned long throttle_start; ++ unsigned char resubmit_to_unthrottle; /* Leftover data from last operation */ ++ unsigned char *throttle_data; ++ int td_len; ++ int td_busy; + }; + + /* global params controlling max sizes for read, write, control */ +@@ -166,6 +173,96 @@ + + #define ACM_READY(acm) (acm && acm->dev && acm->used) + ++ ++/* ++ * Helper functions to optimize throttleing ++ */ ++static int ++acm_fill_tty(struct urb *urb, struct tty_struct *tty, unsigned char *data, int length) ++{ ++ struct acm *acm = urb->context; ++ int n = 0; ++ /*printk("acm_fill_tty: %d bytes\n", length);*/ ++ if (!urb->status && !acm->throttle) { ++ for (n = 0; n < length && !acm->throttle; n++) { ++ /* if we insert more than TTY_FLIPBUF_SIZE characters, ++ * we drop them. */ ++ if (tty->flip.count >= TTY_FLIPBUF_SIZE) { ++ tty_flip_buffer_push(tty); ++ } ++ tty_insert_flip_char(tty, data[n], 0); ++ } ++ tty_flip_buffer_push(tty); ++ } ++ /*printk("copied %d bytes.\n", n);*/ ++ return n; ++} ++ ++static int ++acm_shift_if_throttle(unsigned char *data, int *length, int shift_by) ++{ ++ if (shift_by < *length) { ++ dbg("need to shift uncopied %d bytes to front.", *length - shift_by); ++ memmove(data, data + shift_by, *length - shift_by); ++ *length -= shift_by; ++ return 1; ++ } ++ return 0; ++} ++ ++static int ++acm_buffer_if_thottle(struct acm *acm, unsigned char *data, int start, int *length) ++{ ++ int copied = *length; ++ if (start < *length) { ++ int space = TD_SIZE - acm->td_len; ++ int needed = *length - start; ++ copied = (space < needed)? space: needed; ++ dbg("need to push %d to throttle buffer, can copy %d.", ++ needed, copied); ++ memcpy(acm->throttle_data + acm->td_len, data, copied); ++ acm->td_len += copied; ++ *length -= copied; ++ } ++ return copied; ++} ++ ++static int ++acm_empty_throttle(struct urb *urb, struct tty_struct *tty) ++{ ++ unsigned long flags; ++ struct acm *acm = urb->context; ++ ++ save_flags(flags); ++ cli(); ++ ++ if (acm->td_busy) { ++ restore_flags(flags); ++ return 0; ++ } ++ acm->td_busy = 1; ++ restore_flags(flags); ++ ++ if (acm->td_len > 0) { ++ ++ dbg("acm_empty_throttle: trying to empty throttle buffer: %d bytes.", ++ acm->td_len); ++ ++ /* if there has been something left from previous operations ++ * we try to complete this before looking at the urb */ ++ int copied = acm_fill_tty(urb, tty, acm->throttle_data, acm->td_len); ++ if (acm_shift_if_throttle(acm->throttle_data, &acm->td_len, copied)) { ++ /* we were unable to empty the throttle data, so we can't ++ * copy anything more now */ ++ acm->td_busy = 0; ++ return 0; ++ } ++ acm->td_len = 0; ++ } ++ acm->td_busy = 0; ++ return 1; ++} ++ + /* + * Functions for ACM control messages. + */ +@@ -238,36 +335,40 @@ + struct acm *acm = urb->context; + struct tty_struct *tty = acm->tty; + unsigned char *data = urb->transfer_buffer; +- int i = 0; ++ int copied = 0; ++ int buffered = 0; + + if (!ACM_READY(acm)) return; + +- if (urb->status) ++ if (urb->status) { + dbg("nonzero read bulk status received: %d", urb->status); ++ } + +- if (!urb->status && !acm->throttle) { +- for (i = 0; i < urb->actual_length && !acm->throttle; i++) { +- /* if we insert more than TTY_FLIPBUF_SIZE characters, +- * we drop them. */ +- if (tty->flip.count >= TTY_FLIPBUF_SIZE) { +- tty_flip_buffer_push(tty); +- } +- tty_insert_flip_char(tty, data[i], 0); +- } +- tty_flip_buffer_push(tty); ++ dbg("acm_read_bulk, calling acm_empty_throttle()"); ++ if (!acm_empty_throttle(urb, tty)) { ++ dbg("could not empty throttle buffer, entering throttle state, acm->td_busy: %d.", acm->td_busy); + } + ++ /* got here, either there was nothing in the throttle data or it could ++ * all be copied without throttleing again */ ++ copied = acm_fill_tty(urb, tty, data, urb->actual_length); + if (acm->throttle) { +- memmove(data, data + i, urb->actual_length - i); +- urb->actual_length -= i; +- return; ++ int length = urb->actual_length; ++ buffered = acm_buffer_if_thottle(acm, data, copied, &urb->actual_length); ++ if (buffered < length - copied ++ && acm_shift_if_throttle(data, &urb->actual_length, copied + buffered)) { ++ printk("need to resubmit to unthrottle\n"); ++ acm->resubmit_to_unthrottle = 1; ++ return; ++ } + } + + urb->actual_length = 0; + urb->dev = acm->dev; + +- if (usb_submit_urb(urb)) ++ if (usb_submit_urb(urb)) { + dbg("failed resubmitting read urb"); ++ } + } + + static void acm_write_bulk(struct urb *urb) +@@ -330,7 +431,12 @@ + + acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS); + +- /* force low_latency on so that our tty_push actually forces the data through, ++ acm->resubmit_to_unthrottle = 0; ++ acm->td_len = 0; ++ acm->td_busy = 0; ++ acm->throttle_data = kmalloc(TD_SIZE * sizeof (*acm->throttle_data), GFP_KERNEL); ++ ++ /* force low_latency on so that our tty_push actually forces the data through, + otherwise it is scheduled, and with high data rates data can get lost. */ + tty->low_latency = 1; + +@@ -352,6 +458,7 @@ + } else { + tty_unregister_devfs(&acm_tty_driver, acm->minor); + acm_table[acm->minor] = NULL; ++ kfree(acm->throttle_data); + kfree(acm); + } + } +@@ -363,8 +470,16 @@ + struct acm *acm = tty->driver_data; + + if (!ACM_READY(acm)) return -EINVAL; +- if (acm->writeurb.status == -EINPROGRESS) return 0; +- if (!count) return 0; ++ ++ if (acm->writeurb.status == -EINPROGRESS) { ++ dbg("tty_write in progress"); ++ return 0; ++ } ++ ++ if (!count) { ++ dbg("tty_write: nothing to write"); ++ return 0; ++ } + + count = (count > acm->writesize) ? acm->writesize : count; + +@@ -401,16 +516,32 @@ + { + struct acm *acm = tty->driver_data; + if (!ACM_READY(acm)) return; ++ dbg("acm_tty_throttle ON %ld ---> %ld", jiffies-acm->throttle_start, jiffies); + acm->throttle = 1; ++ acm->throttle_start = jiffies; + } + + static void acm_tty_unthrottle(struct tty_struct *tty) + { + struct acm *acm = tty->driver_data; + if (!ACM_READY(acm)) return; ++ dbg("acm_tty_throttle OFF %ld ---> %ld", jiffies, jiffies-acm->throttle_start); + acm->throttle = 0; +- if (acm->readurb.status != -EINPROGRESS) ++ ++ dbg("acm_tty_unthrottle, calling acm_empty_throttle()"); ++ if (!acm_empty_throttle(&acm->readurb, tty)) { ++ if (acm->td_busy) { ++ printk("***** pending acm_empty_throttle!\n"); ++ } else { ++ dbg("throttle not emptied.\n"); ++ } ++ } ++ ++ if (acm->resubmit_to_unthrottle != 0) { ++ dbg("resubmit_to_unthrottle: acm_read_bulk"); ++ acm->resubmit_to_unthrottle = 0; + acm_read_bulk(&acm->readurb); ++ } + } + + static void acm_tty_break_ctl(struct tty_struct *tty, int state) |