diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-10-12 15:27:22 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-10-12 15:27:22 -0700 |
| commit | b028410f2696cd155f5a7fe9b7f016089a0299b0 (patch) | |
| tree | efc999f34bddc71e44dc6d80a210b54edb7573fd | |
| parent | 06f2db291dfede5b3cb07f7634bed7fa10363c5f (diff) | |
| download | patches-b028410f2696cd155f5a7fe9b7f016089a0299b0.tar.gz | |
build fixes
19 files changed, 3637 insertions, 5 deletions
@@ -21,11 +21,26 @@ tty.current/tty-fix-vt_compat_ioctl.patch ################################# # USB patches for 2.6.32 ################################# +usb.current/usb-musb-invert-arch-depend-string.patch +usb.current/usb-rename-documentation-abi-...-sysfs-class-usb_host.patch +usb.current/usb-wusb-don-t-use-the-stack-to-read-security-descriptor.patch +usb.current/usb-whci-hcd-handle-early-deletion-of-endpoints.patch +usb.current/usb-whci-hcd-always-do-an-update-after-processing-a-halted-qtd.patch +usb.current/usb-option-support-for-airplus-mcd650-datacard.patch +usb.current/usb-ehci-fix-ist-boundary-checking-interval-math.patch ################################# # Staging patches for 2.6.32 ################################# +staging.current/staging-iio-fix-missing-include-linux-sched.h.patch +staging.current/staging-comedi-fix-sched.h-build-breakage.patch +staging.current/staging-b3dfg-fix-sched.h-build-breakage.patch +staging.current/staging-poch-fix-sched.h-build-breakage.patch +staging.current/staging-vme-fix-sched.h-build-breakage.patch +staging.current/staging-complete-sched.h-removal-from-interrupt.h.patch +staging.current/staging-et131x-correct-wrap-bit-handling.patch +staging.current/staging-et131x-fix-the-add_10bit-macro.patch ##################################################################### @@ -48,6 +63,7 @@ tty/jsm-removing-unused-jsm_channel-ch_wopen-field.patch tty/jsm-removing-the-field-jsm_board-intr_count.patch tty/tty-const-constify-remaining-tty_operations.patch +tty/tty-esp-remove-broken-driver.patch ################################# # USB stuff (after 2.6.32 is out) @@ -127,4 +143,3 @@ staging/staging-android-delete-android-drivers.patch #tty.work/serial-f81216-helper - diff --git a/staging.current/staging-b3dfg-fix-sched.h-build-breakage.patch b/staging.current/staging-b3dfg-fix-sched.h-build-breakage.patch new file mode 100644 index 00000000000000..31542c97014783 --- /dev/null +++ b/staging.current/staging-b3dfg-fix-sched.h-build-breakage.patch @@ -0,0 +1,25 @@ +From foo@baz Mon Oct 12 14:59:33 PDT 2009 +Date: Mon, 12 Oct 2009 14:59:33 -0700 +To: Greg KH <greg@kroah.com> +From: Greg Kroah-Hartman <gregkh@suse.de> +Subject: Staging: b3dfg: fix sched.h build breakage + +commit d43c36dc removed sched.h from interrupt.h. This broke the +b3dfg driver. This patch fixes this. + +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/b3dfg/b3dfg.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/staging/b3dfg/b3dfg.c ++++ b/drivers/staging/b3dfg/b3dfg.c +@@ -36,6 +36,7 @@ + #include <linux/wait.h> + #include <linux/mm.h> + #include <linux/uaccess.h> ++#include <linux/sched.h> + + static unsigned int b3dfg_nbuf = 2; + diff --git a/staging.current/staging-comedi-fix-sched.h-build-breakage.patch b/staging.current/staging-comedi-fix-sched.h-build-breakage.patch new file mode 100644 index 00000000000000..e99bc1a2ac3772 --- /dev/null +++ b/staging.current/staging-comedi-fix-sched.h-build-breakage.patch @@ -0,0 +1,47 @@ +From foo@baz Mon Oct 12 14:58:16 PDT 2009 +Date: Mon, 12 Oct 2009 14:58:16 -0700 +To: Greg KH <greg@kroah.com> +From: Greg Kroah-Hartman <gregkh@suse.de> +Subject: Staging: comedi: fix sched.h build breakage + +commit d43c36dc removed sched.h from interrupt.h. This broke some of +the comedi drivers. This patch fixes this. + +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/comedi/drivers/me_daq.c | 1 + + drivers/staging/comedi/drivers/ni_mio_common.c | 1 + + drivers/staging/comedi/drivers/ni_pcidio.c | 1 + + 3 files changed, 3 insertions(+) + +--- a/drivers/staging/comedi/drivers/me_daq.c ++++ b/drivers/staging/comedi/drivers/me_daq.c +@@ -51,6 +51,7 @@ from http://www.comedi.org + */ + + #include <linux/interrupt.h> ++#include <linux/sched.h> + #include "../comedidev.h" + + #include "comedi_pci.h" +--- a/drivers/staging/comedi/drivers/ni_mio_common.c ++++ b/drivers/staging/comedi/drivers/ni_mio_common.c +@@ -62,6 +62,7 @@ + /* #define DEBUG_STATUS_B */ + + #include <linux/interrupt.h> ++#include <linux/sched.h> + #include "8255.h" + #include "mite.h" + #include "comedi_fc.h" +--- a/drivers/staging/comedi/drivers/ni_pcidio.c ++++ b/drivers/staging/comedi/drivers/ni_pcidio.c +@@ -70,6 +70,7 @@ comedi_nonfree_firmware tarball availabl + /* #define DEBUG_FLAGS */ + + #include <linux/interrupt.h> ++#include <linux/sched.h> + #include "../comedidev.h" + + #include "mite.h" diff --git a/staging.current/staging-complete-sched.h-removal-from-interrupt.h.patch b/staging.current/staging-complete-sched.h-removal-from-interrupt.h.patch new file mode 100644 index 00000000000000..c65fda6615c603 --- /dev/null +++ b/staging.current/staging-complete-sched.h-removal-from-interrupt.h.patch @@ -0,0 +1,49 @@ +From jeffm@suse.com Mon Oct 12 14:43:01 2009 +From: Jeff Mahoney <jeffm@suse.com> +Date: Mon, 12 Oct 2009 17:10:34 -0400 +Subject: staging: Complete sched.h removal from interrupt.h +To: Greg KH <gregkh@suse.de> +Message-ID: <4AD39B4A.6030305@suse.com> + +Commit d43c36dc removed sched.h from interrupt.h and distributed sched.h +to users which needed it. This finishes it up for staging. + +Signed-off-by: Jeff Mahoney <jeffm@suse.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/hv/osd.c | 1 + + drivers/staging/iio/industrialio-core.c | 1 + + drivers/staging/sep/sep_driver.c | 1 + + 3 files changed, 3 insertions(+) + +--- a/drivers/staging/hv/osd.c ++++ b/drivers/staging/hv/osd.c +@@ -30,6 +30,7 @@ + #include <linux/ioport.h> + #include <linux/irq.h> + #include <linux/interrupt.h> ++#include <linux/sched.h> + #include <linux/wait.h> + #include <linux/spinlock.h> + #include <linux/workqueue.h> +--- a/drivers/staging/iio/industrialio-core.c ++++ b/drivers/staging/iio/industrialio-core.c +@@ -19,6 +19,7 @@ + #include <linux/interrupt.h> + #include <linux/poll.h> + #include <linux/sched.h> ++#include <linux/wait.h> + #include <linux/cdev.h> + #include "iio.h" + #include "trigger_consumer.h" +--- a/drivers/staging/sep/sep_driver.c ++++ b/drivers/staging/sep/sep_driver.c +@@ -38,6 +38,7 @@ + #include <linux/mm.h> + #include <linux/poll.h> + #include <linux/wait.h> ++#include <linux/sched.h> + #include <linux/pci.h> + #include <linux/firmware.h> + #include <asm/ioctl.h> diff --git a/staging.current/staging-et131x-correct-wrap-bit-handling.patch b/staging.current/staging-et131x-correct-wrap-bit-handling.patch new file mode 100644 index 00000000000000..ff1427e47640b9 --- /dev/null +++ b/staging.current/staging-et131x-correct-wrap-bit-handling.patch @@ -0,0 +1,46 @@ +From alan@linux.intel.com Mon Oct 12 15:01:40 2009 +From: Alan Cox <alan@linux.intel.com> +Date: Mon, 12 Oct 2009 15:38:17 +0100 +Subject: Staging: et131x: Correct WRAP bit handling +To: greg@kroah.com, linux-kernel@vger.kernel.org +Message-ID: <20091012143813.20944.66683.stgit@localhost.localdomain> + + +add_10bit loses the existing wrap value + +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/et131x/et1310_rx.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +--- a/drivers/staging/et131x/et1310_rx.c ++++ b/drivers/staging/et131x/et1310_rx.c +@@ -1177,12 +1177,20 @@ void et131x_handle_recv_interrupt(struct + + static inline u32 bump_fbr(u32 *fbr, u32 limit) + { +- u32 v = *fbr; +- add_10bit(&v, 1); +- if (v > limit) +- v = (*fbr & ~ET_DMA10_MASK) ^ ET_DMA10_WRAP; +- *fbr = v; +- return v; ++ u32 v = *fbr; ++ v++; ++ /* This works for all cases where limit < 1024. The 1023 case ++ works because 1023++ is 1024 which means the if condition is not ++ taken but the carry of the bit into the wrap bit toggles the wrap ++ value correctly */ ++ if ((v & ET_DMA10_MASK) > limit) { ++ v &= ~ET_DMA10_MASK; ++ v ^= ET_DMA10_WRAP; ++ } ++ /* For the 1023 case */ ++ v &= (ET_DMA10_MASK|ET_DMA10_WRAP); ++ *fbr = v; ++ return v; + } + + /** diff --git a/staging.current/staging-et131x-fix-the-add_10bit-macro.patch b/staging.current/staging-et131x-fix-the-add_10bit-macro.patch new file mode 100644 index 00000000000000..5494c94e621cde --- /dev/null +++ b/staging.current/staging-et131x-fix-the-add_10bit-macro.patch @@ -0,0 +1,29 @@ +From alan@linux.intel.com Mon Oct 12 15:01:52 2009 +From: Alan Cox <alan@linux.intel.com> +Date: Mon, 12 Oct 2009 15:38:26 +0100 +Subject: Staging: et131x: Fix the add_10bit macro +To: greg@kroah.com, linux-kernel@vger.kernel.org +Message-ID: <20091012143823.20944.3745.stgit@localhost.localdomain> + + +Duh.. we need to preserve the wrap bit when adding. + +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/staging/et131x/et1310_address_map.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/et131x/et1310_address_map.h ++++ b/drivers/staging/et131x/et1310_address_map.h +@@ -223,7 +223,7 @@ typedef union _TXDMA_PR_NUM_DES_t { + + extern inline void add_10bit(u32 *v, int n) + { +- *v = INDEX10(*v + n); ++ *v = INDEX10(*v + n) | (*v & ET_DMA10_WRAP); + } + + /* diff --git a/staging.current/staging-iio-fix-missing-include-linux-sched.h.patch b/staging.current/staging-iio-fix-missing-include-linux-sched.h.patch new file mode 100644 index 00000000000000..7d3222b14f2b74 --- /dev/null +++ b/staging.current/staging-iio-fix-missing-include-linux-sched.h.patch @@ -0,0 +1,30 @@ +From jic23@cam.ac.uk Mon Oct 12 14:20:30 2009 +From: Jonathan Cameron <jic23@cam.ac.uk> +Date: Mon, 12 Oct 2009 19:18:09 +0100 +Subject: Staging: iio: Fix missing include <linux/sched.h> +Cc: Greg Kroah-Hartman <gregkh@suse.de>, devel@linuxdriverproject.org +Message-ID: <4AD372E1.50002@cam.ac.uk> + + +linux/sched.h include was removed form linux/poll.h by +commmit a99bbaf5ee6bad1aca0c88ea65ec6e5373e86184 + +Required for definition of TASK_INTERRUPTIBLE amongst others + +From: Jonathan Cameron <jic23@cam.ac.uk> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- a/drivers/staging/iio/industrialio-core.c ++++ b/drivers/staging/iio/industrialio-core.c +@@ -18,6 +18,7 @@ + #include <linux/fs.h> + #include <linux/interrupt.h> + #include <linux/poll.h> ++#include <linux/sched.h> + #include <linux/cdev.h> + #include "iio.h" + #include "trigger_consumer.h" +-- +1.6.3.3 + diff --git a/staging.current/staging-poch-fix-sched.h-build-breakage.patch b/staging.current/staging-poch-fix-sched.h-build-breakage.patch new file mode 100644 index 00000000000000..8103d3efb2746d --- /dev/null +++ b/staging.current/staging-poch-fix-sched.h-build-breakage.patch @@ -0,0 +1,25 @@ +From foo@baz Mon Oct 12 14:59:56 PDT 2009 +Date: Mon, 12 Oct 2009 14:59:56 -0700 +To: Greg KH <greg@kroah.com> +From: Greg Kroah-Hartman <gregkh@suse.de> +Subject: Staging: poch: fix sched.h build breakage + +commit d43c36dc removed sched.h from interrupt.h. This broke the +poch driver. This patch fixes this. + +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/staging/poch/poch.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/staging/poch/poch.c ++++ b/drivers/staging/poch/poch.c +@@ -20,6 +20,7 @@ + #include <linux/init.h> + #include <linux/ioctl.h> + #include <linux/io.h> ++#include <linux/sched.h> + + #include "poch.h" + diff --git a/staging.current/staging-vme-fix-sched.h-build-breakage.patch b/staging.current/staging-vme-fix-sched.h-build-breakage.patch new file mode 100644 index 00000000000000..2083aa5e135f10 --- /dev/null +++ b/staging.current/staging-vme-fix-sched.h-build-breakage.patch @@ -0,0 +1,35 @@ +From foo@baz Mon Oct 12 15:00:08 PDT 2009 +Date: Mon, 12 Oct 2009 15:00:08 -0700 +To: Greg KH <greg@kroah.com> +From: Greg Kroah-Hartman <gregkh@suse.de> +Subject: Staging: vme: fix sched.h build breakage + +commit d43c36dc removed sched.h from interrupt.h. This broke the +vme drivers. This patch fixes them. + +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/staging/vme/bridges/vme_ca91cx42.c | 1 + + drivers/staging/vme/bridges/vme_tsi148.c | 1 + + 2 files changed, 2 insertions(+) + +--- a/drivers/staging/vme/bridges/vme_ca91cx42.c ++++ b/drivers/staging/vme/bridges/vme_ca91cx42.c +@@ -25,6 +25,7 @@ + #include <linux/poll.h> + #include <linux/interrupt.h> + #include <linux/spinlock.h> ++#include <linux/sched.h> + #include <asm/time.h> + #include <asm/io.h> + #include <asm/uaccess.h> +--- a/drivers/staging/vme/bridges/vme_tsi148.c ++++ b/drivers/staging/vme/bridges/vme_tsi148.c +@@ -25,6 +25,7 @@ + #include <linux/dma-mapping.h> + #include <linux/interrupt.h> + #include <linux/spinlock.h> ++#include <linux/sched.h> + #include <asm/time.h> + #include <asm/io.h> + #include <asm/uaccess.h> diff --git a/staging/staging-b3dfg-remove-check-for-pci-bus-master.patch b/staging/staging-b3dfg-remove-check-for-pci-bus-master.patch index 2feca8b9410871..80defe2db779e8 100644 --- a/staging/staging-b3dfg-remove-check-for-pci-bus-master.patch +++ b/staging/staging-b3dfg-remove-check-for-pci-bus-master.patch @@ -18,7 +18,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- a/drivers/staging/b3dfg/b3dfg.c +++ b/drivers/staging/b3dfg/b3dfg.c -@@ -467,7 +467,6 @@ static int get_wand_status(struct b3dfg_ +@@ -468,7 +468,6 @@ static int get_wand_status(struct b3dfg_ static int enable_transmission(struct b3dfg_dev *fgdev) { @@ -26,7 +26,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> unsigned long flags; struct device *dev = &fgdev->pdev->dev; -@@ -479,17 +478,6 @@ static int enable_transmission(struct b3 +@@ -480,17 +479,6 @@ static int enable_transmission(struct b3 return -EINVAL; } diff --git a/staging/staging-comedi-trivial-fix-of-a-very-frequent-spelling-mistake.patch b/staging/staging-comedi-trivial-fix-of-a-very-frequent-spelling-mistake.patch index 61558142e0c382..81c63775c12178 100644 --- a/staging/staging-comedi-trivial-fix-of-a-very-frequent-spelling-mistake.patch +++ b/staging/staging-comedi-trivial-fix-of-a-very-frequent-spelling-mistake.patch @@ -113,7 +113,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> cmd->scan_begin_src != TRIG_TIMER) --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c -@@ -2206,7 +2206,7 @@ static int ni_ai_cmdtest(struct comedi_d +@@ -2207,7 +2207,7 @@ static int ni_ai_cmdtest(struct comedi_d /* step 2: make sure trigger sources are unique and mutually compatible */ @@ -124,7 +124,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> err++; --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c -@@ -794,7 +794,7 @@ static int ni_pcidio_cmdtest(struct come +@@ -795,7 +795,7 @@ static int ni_pcidio_cmdtest(struct come /* step 2: make sure trigger sources are unique and mutually compatible */ diff --git a/tty/tty-esp-remove-broken-driver.patch b/tty/tty-esp-remove-broken-driver.patch new file mode 100644 index 00000000000000..bb72d074410073 --- /dev/null +++ b/tty/tty-esp-remove-broken-driver.patch @@ -0,0 +1,2865 @@ +From alan@linux.intel.com Mon Oct 12 15:12:35 2009 +From: Alan Cox <alan@linux.intel.com> +Date: Fri, 09 Oct 2009 12:56:41 +0100 +Subject: tty: esp: remove broken driver +To: greg@kroah.com, linux-serial@vger.kernel.org, linux=kernel@vger.kernel.org +Message-ID: <20091009115633.6007.5807.stgit@localhost.localdomain> + + +The ESP driver has been marked broken for years. It's an old ISA device +that clearly nobody cares about any more. Remove it + +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + Documentation/serial/hayes-esp.txt | 154 -- + drivers/char/Kconfig | 13 + drivers/char/Makefile | 1 + drivers/char/esp.c | 2533 ------------------------------------- + include/linux/hayesesp.h | 114 - + 5 files changed, 2815 deletions(-) + +--- a/Documentation/serial/hayes-esp.txt ++++ /dev/null +@@ -1,154 +0,0 @@ +-HAYES ESP DRIVER VERSION 2.1 +- +-A big thanks to the people at Hayes, especially Alan Adamson. Their support +-has enabled me to provide enhancements to the driver. +- +-Please report your experiences with this driver to me (arobinso@nyx.net). I +-am looking for both positive and negative feedback. +- +-*** IMPORTANT CHANGES FOR 2.1 *** +-Support for PIO mode. Five situations will cause PIO mode to be used: +-1) A multiport card is detected. PIO mode will always be used. (8 port cards +-do not support DMA). +-2) The DMA channel is set to an invalid value (anything other than 1 or 3). +-3) The DMA buffer/channel could not be allocated. The port will revert to PIO +-mode until it is reopened. +-4) Less than a specified number of bytes need to be transferred to/from the +-FIFOs. PIO mode will be used for that transfer only. +-5) A port needs to do a DMA transfer and another port is already using the +-DMA channel. PIO mode will be used for that transfer only. +- +-Since the Hayes ESP seems to conflict with other cards (notably sound cards) +-when using DMA, DMA is turned off by default. To use DMA, it must be turned +-on explicitly, either with the "dma=" option described below or with +-setserial. A multiport card can be forced into DMA mode by using setserial; +-however, most multiport cards don't support DMA. +- +-The latest version of setserial allows the enhanced configuration of the ESP +-card to be viewed and modified. +-*** +- +-This package contains the files needed to compile a module to support the Hayes +-ESP card. The drivers are basically a modified version of the serial drivers. +- +-Features: +- +-- Uses the enhanced mode of the ESP card, allowing a wider range of +- interrupts and features than compatibility mode +-- Uses DMA and 16 bit PIO mode to transfer data to and from the ESP's FIFOs, +- reducing CPU load +-- Supports primary and secondary ports +- +- +-If the driver is compiled as a module, the IRQs to use can be specified by +-using the irq= option. The format is: +- +-irq=[0x100],[0x140],[0x180],[0x200],[0x240],[0x280],[0x300],[0x380] +- +-The address in brackets is the base address of the card. The IRQ of +-nonexistent cards can be set to 0. If an IRQ of a card that does exist is set +-to 0, the driver will attempt to guess at the correct IRQ. For example, to set +-the IRQ of the card at address 0x300 to 12, the insmod command would be: +- +-insmod esp irq=0,0,0,0,0,0,12,0 +- +-The custom divisor can be set by using the divisor= option. The format is the +-same as for the irq= option. Each divisor value is a series of hex digits, +-with each digit representing the divisor to use for a corresponding port. The +-divisor value is constructed RIGHT TO LEFT. Specifying a nonzero divisor value +-will automatically set the spd_cust flag. To calculate the divisor to use for +-a certain baud rate, divide the port's base baud (generally 921600) by the +-desired rate. For example, to set the divisor of the primary port at 0x300 to +-4 and the divisor of the secondary port at 0x308 to 8, the insmod command would +-be: +- +-insmod esp divisor=0,0,0,0,0,0,0x84,0 +- +-The dma= option can be used to set the DMA channel. The channel can be either +-1 or 3. Specifying any other value will force the driver to use PIO mode. +-For example, to set the DMA channel to 3, the insmod command would be: +- +-insmod esp dma=3 +- +-The rx_trigger= and tx_trigger= options can be used to set the FIFO trigger +-levels. They specify when the ESP card should send an interrupt. Larger +-values will decrease the number of interrupts; however, a value too high may +-result in data loss. Valid values are 1 through 1023, with 768 being the +-default. For example, to set the receive trigger level to 512 bytes and the +-transmit trigger level to 700 bytes, the insmod command would be: +- +-insmod esp rx_trigger=512 tx_trigger=700 +- +-The flow_off= and flow_on= options can be used to set the hardware flow off/ +-flow on levels. The flow on level must be lower than the flow off level, and +-the flow off level should be higher than rx_trigger. Valid values are 1 +-through 1023, with 1016 being the default flow off level and 944 being the +-default flow on level. For example, to set the flow off level to 1000 bytes +-and the flow on level to 935 bytes, the insmod command would be: +- +-insmod esp flow_off=1000 flow_on=935 +- +-The rx_timeout= option can be used to set the receive timeout value. This +-value indicates how long after receiving the last character that the ESP card +-should wait before signalling an interrupt. Valid values are 0 though 255, +-with 128 being the default. A value too high will increase latency, and a +-value too low will cause unnecessary interrupts. For example, to set the +-receive timeout to 255, the insmod command would be: +- +-insmod esp rx_timeout=255 +- +-The pio_threshold= option sets the threshold (in number of characters) for +-using PIO mode instead of DMA mode. For example, if this value is 32, +-transfers of 32 bytes or less will always use PIO mode. +- +-insmod esp pio_threshold=32 +- +-Multiple options can be listed on the insmod command line by separating each +-option with a space. For example: +- +-insmod esp dma=3 trigger=512 +- +-The esp module can be automatically loaded when needed. To cause this to +-happen, add the following lines to /etc/modprobe.conf (replacing the last line +-with options for your configuration): +- +-alias char-major-57 esp +-alias char-major-58 esp +-options esp irq=0,0,0,0,0,0,3,0 divisor=0,0,0,0,0,0,0x4,0 +- +-You may also need to run 'depmod -a'. +- +-Devices must be created manually. To create the devices, note the output from +-the module after it is inserted. The output will appear in the location where +-kernel messages usually appear (usually /var/adm/messages). Create two devices +-for each 'tty' mentioned, one with major of 57 and the other with major of 58. +-The minor number should be the same as the tty number reported. The commands +-would be (replace ? with the tty number): +- +-mknod /dev/ttyP? c 57 ? +-mknod /dev/cup? c 58 ? +- +-For example, if the following line appears: +- +-Oct 24 18:17:23 techno kernel: ttyP8 at 0x0140 (irq = 3) is an ESP primary port +- +-...two devices should be created: +- +-mknod /dev/ttyP8 c 57 8 +-mknod /dev/cup8 c 58 8 +- +-You may need to set the permissions on the devices: +- +-chmod 666 /dev/ttyP* +-chmod 666 /dev/cup* +- +-The ESP module and the serial module should not conflict (they can be used at +-the same time). After the ESP module has been loaded the ports on the ESP card +-will no longer be accessible by the serial driver. +- +-If I/O errors are experienced when accessing the port, check for IRQ and DMA +-conflicts ('cat /proc/interrupts' and 'cat /proc/dma' for a list of IRQs and +-DMAs currently in use). +- +-Enjoy! +-Andrew J. Robinson <arobinso@nyx.net> +--- a/drivers/char/esp.c ++++ /dev/null +@@ -1,2533 +0,0 @@ +-/* +- * esp.c - driver for Hayes ESP serial cards +- * +- * --- Notices from serial.c, upon which this driver is based --- +- * +- * Copyright (C) 1991, 1992 Linus Torvalds +- * +- * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now +- * much more extensible to support other serial cards based on the +- * 16450/16550A UART's. Added support for the AST FourPort and the +- * Accent Async board. +- * +- * set_serial_info fixed to set the flags, custom divisor, and uart +- * type fields. Fix suggested by Michael K. Johnson 12/12/92. +- * +- * 11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk> +- * +- * 03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk> +- * +- * rs_set_termios fixed to look also for changes of the input +- * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK. +- * Bernd Anhäupl 05/17/96. +- * +- * --- End of notices from serial.c --- +- * +- * Support for the ESP serial card by Andrew J. Robinson +- * <arobinso@nyx.net> (Card detection routine taken from a patch +- * by Dennis J. Boylan). Patches to allow use with 2.1.x contributed +- * by Chris Faylor. +- * +- * Most recent changes: (Andrew J. Robinson) +- * Support for PIO mode. This allows the driver to work properly with +- * multiport cards. +- * +- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - +- * several cleanups, use module_init/module_exit, etc +- * +- * This module exports the following rs232 io functions: +- * +- * int espserial_init(void); +- */ +- +-#include <linux/module.h> +-#include <linux/errno.h> +-#include <linux/signal.h> +-#include <linux/sched.h> +-#include <linux/interrupt.h> +-#include <linux/tty.h> +-#include <linux/tty_flip.h> +-#include <linux/serial.h> +-#include <linux/serialP.h> +-#include <linux/serial_reg.h> +-#include <linux/major.h> +-#include <linux/string.h> +-#include <linux/fcntl.h> +-#include <linux/ptrace.h> +-#include <linux/ioport.h> +-#include <linux/mm.h> +-#include <linux/init.h> +-#include <linux/delay.h> +-#include <linux/bitops.h> +- +-#include <asm/system.h> +-#include <linux/io.h> +- +-#include <asm/dma.h> +-#include <linux/slab.h> +-#include <linux/uaccess.h> +- +-#include <linux/hayesesp.h> +- +-#define NR_PORTS 64 /* maximum number of ports */ +-#define NR_PRIMARY 8 /* maximum number of primary ports */ +-#define REGION_SIZE 8 /* size of io region to request */ +- +-/* The following variables can be set by giving module options */ +-static int irq[NR_PRIMARY]; /* IRQ for each base port */ +-static unsigned int divisor[NR_PRIMARY]; /* custom divisor for each port */ +-static unsigned int dma = ESP_DMA_CHANNEL; /* DMA channel */ +-static unsigned int rx_trigger = ESP_RX_TRIGGER; +-static unsigned int tx_trigger = ESP_TX_TRIGGER; +-static unsigned int flow_off = ESP_FLOW_OFF; +-static unsigned int flow_on = ESP_FLOW_ON; +-static unsigned int rx_timeout = ESP_RX_TMOUT; +-static unsigned int pio_threshold = ESP_PIO_THRESHOLD; +- +-MODULE_LICENSE("GPL"); +- +-module_param_array(irq, int, NULL, 0); +-module_param_array(divisor, uint, NULL, 0); +-module_param(dma, uint, 0); +-module_param(rx_trigger, uint, 0); +-module_param(tx_trigger, uint, 0); +-module_param(flow_off, uint, 0); +-module_param(flow_on, uint, 0); +-module_param(rx_timeout, uint, 0); +-module_param(pio_threshold, uint, 0); +- +-/* END */ +- +-static char *dma_buffer; +-static int dma_bytes; +-static struct esp_pio_buffer *free_pio_buf; +- +-#define DMA_BUFFER_SZ 1024 +- +-#define WAKEUP_CHARS 1024 +- +-static char serial_name[] __initdata = "ESP serial driver"; +-static char serial_version[] __initdata = "2.2"; +- +-static struct tty_driver *esp_driver; +- +-/* +- * Serial driver configuration section. Here are the various options: +- * +- * SERIAL_PARANOIA_CHECK +- * Check the magic number for the esp_structure where +- * ever possible. +- */ +- +-#undef SERIAL_PARANOIA_CHECK +-#define SERIAL_DO_RESTART +- +-#undef SERIAL_DEBUG_INTR +-#undef SERIAL_DEBUG_OPEN +-#undef SERIAL_DEBUG_FLOW +- +-#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) +-#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ +- tty->name, info->port.flags, \ +- serial_driver.refcount, \ +- info->port.count, tty->count, s) +-#else +-#define DBG_CNT(s) +-#endif +- +-static struct esp_struct *ports; +- +-static void change_speed(struct esp_struct *info); +-static void rs_wait_until_sent(struct tty_struct *, int); +- +-/* +- * The ESP card has a clock rate of 14.7456 MHz (that is, 2**ESPC_SCALE +- * times the normal 1.8432 Mhz clock of most serial boards). +- */ +-#define BASE_BAUD ((1843200 / 16) * (1 << ESPC_SCALE)) +- +-/* Standard COM flags (except for COM4, because of the 8514 problem) */ +-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) +- +-static inline int serial_paranoia_check(struct esp_struct *info, +- char *name, const char *routine) +-{ +-#ifdef SERIAL_PARANOIA_CHECK +- static const char badmagic[] = KERN_WARNING +- "Warning: bad magic number for serial struct (%s) in %s\n"; +- static const char badinfo[] = KERN_WARNING +- "Warning: null esp_struct for (%s) in %s\n"; +- +- if (!info) { +- printk(badinfo, name, routine); +- return 1; +- } +- if (info->magic != ESP_MAGIC) { +- printk(badmagic, name, routine); +- return 1; +- } +-#endif +- return 0; +-} +- +-static inline unsigned int serial_in(struct esp_struct *info, int offset) +-{ +- return inb(info->io_port + offset); +-} +- +-static inline void serial_out(struct esp_struct *info, int offset, +- unsigned char value) +-{ +- outb(value, info->io_port+offset); +-} +- +-/* +- * ------------------------------------------------------------ +- * rs_stop() and rs_start() +- * +- * This routines are called before setting or resetting tty->stopped. +- * They enable or disable transmitter interrupts, as necessary. +- * ------------------------------------------------------------ +- */ +-static void rs_stop(struct tty_struct *tty) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +- +- if (serial_paranoia_check(info, tty->name, "rs_stop")) +- return; +- +- spin_lock_irqsave(&info->lock, flags); +- if (info->IER & UART_IER_THRI) { +- info->IER &= ~UART_IER_THRI; +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- } +- spin_unlock_irqrestore(&info->lock, flags); +-} +- +-static void rs_start(struct tty_struct *tty) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +- +- if (serial_paranoia_check(info, tty->name, "rs_start")) +- return; +- +- spin_lock_irqsave(&info->lock, flags); +- if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { +- info->IER |= UART_IER_THRI; +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- } +- spin_unlock_irqrestore(&info->lock, flags); +-} +- +-/* +- * ---------------------------------------------------------------------- +- * +- * Here starts the interrupt handling routines. All of the following +- * subroutines are declared as inline and are folded into +- * rs_interrupt(). They were separated out for readability's sake. +- * +- * Note: rs_interrupt() is a "fast" interrupt, which means that it +- * runs with interrupts turned off. People who may want to modify +- * rs_interrupt() should try to keep the interrupt handler as fast as +- * possible. After you are done making modifications, it is not a bad +- * idea to do: +- * +- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c +- * +- * and look at the resulting assemble code in serial.s. +- * +- * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 +- * ----------------------------------------------------------------------- +- */ +- +-static DEFINE_SPINLOCK(pio_lock); +- +-static inline struct esp_pio_buffer *get_pio_buffer(void) +-{ +- struct esp_pio_buffer *buf; +- unsigned long flags; +- +- spin_lock_irqsave(&pio_lock, flags); +- if (free_pio_buf) { +- buf = free_pio_buf; +- free_pio_buf = buf->next; +- } else { +- buf = kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC); +- } +- spin_unlock_irqrestore(&pio_lock, flags); +- return buf; +-} +- +-static inline void release_pio_buffer(struct esp_pio_buffer *buf) +-{ +- unsigned long flags; +- spin_lock_irqsave(&pio_lock, flags); +- buf->next = free_pio_buf; +- free_pio_buf = buf; +- spin_unlock_irqrestore(&pio_lock, flags); +-} +- +-static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) +-{ +- struct tty_struct *tty = info->port.tty; +- int i; +- struct esp_pio_buffer *pio_buf; +- struct esp_pio_buffer *err_buf; +- unsigned char status_mask; +- +- pio_buf = get_pio_buffer(); +- +- if (!pio_buf) +- return; +- +- err_buf = get_pio_buffer(); +- +- if (!err_buf) { +- release_pio_buffer(pio_buf); +- return; +- } +- +- status_mask = (info->read_status_mask >> 2) & 0x07; +- +- for (i = 0; i < num_bytes - 1; i += 2) { +- *((unsigned short *)(pio_buf->data + i)) = +- inw(info->io_port + UART_ESI_RX); +- err_buf->data[i] = serial_in(info, UART_ESI_RWS); +- err_buf->data[i + 1] = (err_buf->data[i] >> 3) & status_mask; +- err_buf->data[i] &= status_mask; +- } +- +- if (num_bytes & 0x0001) { +- pio_buf->data[num_bytes - 1] = serial_in(info, UART_ESI_RX); +- err_buf->data[num_bytes - 1] = +- (serial_in(info, UART_ESI_RWS) >> 3) & status_mask; +- } +- +- /* make sure everything is still ok since interrupts were enabled */ +- tty = info->port.tty; +- +- if (!tty) { +- release_pio_buffer(pio_buf); +- release_pio_buffer(err_buf); +- info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; +- return; +- } +- +- status_mask = (info->ignore_status_mask >> 2) & 0x07; +- +- for (i = 0; i < num_bytes; i++) { +- if (!(err_buf->data[i] & status_mask)) { +- int flag = 0; +- +- if (err_buf->data[i] & 0x04) { +- flag = TTY_BREAK; +- if (info->port.flags & ASYNC_SAK) +- do_SAK(tty); +- } else if (err_buf->data[i] & 0x02) +- flag = TTY_FRAME; +- else if (err_buf->data[i] & 0x01) +- flag = TTY_PARITY; +- tty_insert_flip_char(tty, pio_buf->data[i], flag); +- } +- } +- +- tty_schedule_flip(tty); +- +- info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; +- release_pio_buffer(pio_buf); +- release_pio_buffer(err_buf); +-} +- +-static void program_isa_dma(int dma, int dir, unsigned long addr, int len) +-{ +- unsigned long flags; +- +- flags = claim_dma_lock(); +- disable_dma(dma); +- clear_dma_ff(dma); +- set_dma_mode(dma, dir); +- set_dma_addr(dma, addr); +- set_dma_count(dma, len); +- enable_dma(dma); +- release_dma_lock(flags); +-} +- +-static void receive_chars_dma(struct esp_struct *info, int num_bytes) +-{ +- info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; +- dma_bytes = num_bytes; +- info->stat_flags |= ESP_STAT_DMA_RX; +- +- program_isa_dma(dma, DMA_MODE_READ, isa_virt_to_bus(dma_buffer), +- dma_bytes); +- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX); +-} +- +-static inline void receive_chars_dma_done(struct esp_struct *info, +- int status) +-{ +- struct tty_struct *tty = info->port.tty; +- int num_bytes; +- unsigned long flags; +- +- flags = claim_dma_lock(); +- disable_dma(dma); +- clear_dma_ff(dma); +- +- info->stat_flags &= ~ESP_STAT_DMA_RX; +- num_bytes = dma_bytes - get_dma_residue(dma); +- release_dma_lock(flags); +- +- info->icount.rx += num_bytes; +- +- if (num_bytes > 0) { +- tty_insert_flip_string(tty, dma_buffer, num_bytes - 1); +- +- status &= (0x1c & info->read_status_mask); +- +- /* Is the status significant or do we throw the last byte ? */ +- if (!(status & info->ignore_status_mask)) { +- int statflag = 0; +- +- if (status & 0x10) { +- statflag = TTY_BREAK; +- (info->icount.brk)++; +- if (info->port.flags & ASYNC_SAK) +- do_SAK(tty); +- } else if (status & 0x08) { +- statflag = TTY_FRAME; +- info->icount.frame++; +- } else if (status & 0x04) { +- statflag = TTY_PARITY; +- info->icount.parity++; +- } +- tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], +- statflag); +- } +- tty_schedule_flip(tty); +- } +- +- if (dma_bytes != num_bytes) { +- num_bytes = dma_bytes - num_bytes; +- dma_bytes = 0; +- receive_chars_dma(info, num_bytes); +- } else +- dma_bytes = 0; +-} +- +-/* Caller must hold info->lock */ +- +-static inline void transmit_chars_pio(struct esp_struct *info, +- int space_avail) +-{ +- int i; +- struct esp_pio_buffer *pio_buf; +- +- pio_buf = get_pio_buffer(); +- +- if (!pio_buf) +- return; +- +- while (space_avail && info->xmit_cnt) { +- if (info->xmit_tail + space_avail <= ESP_XMIT_SIZE) { +- memcpy(pio_buf->data, +- &(info->xmit_buf[info->xmit_tail]), +- space_avail); +- } else { +- i = ESP_XMIT_SIZE - info->xmit_tail; +- memcpy(pio_buf->data, +- &(info->xmit_buf[info->xmit_tail]), i); +- memcpy(&(pio_buf->data[i]), info->xmit_buf, +- space_avail - i); +- } +- +- info->xmit_cnt -= space_avail; +- info->xmit_tail = (info->xmit_tail + space_avail) & +- (ESP_XMIT_SIZE - 1); +- +- for (i = 0; i < space_avail - 1; i += 2) { +- outw(*((unsigned short *)(pio_buf->data + i)), +- info->io_port + UART_ESI_TX); +- } +- +- if (space_avail & 0x0001) +- serial_out(info, UART_ESI_TX, +- pio_buf->data[space_avail - 1]); +- +- if (info->xmit_cnt) { +- serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); +- serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); +- space_avail = serial_in(info, UART_ESI_STAT1) << 8; +- space_avail |= serial_in(info, UART_ESI_STAT2); +- +- if (space_avail > info->xmit_cnt) +- space_avail = info->xmit_cnt; +- } +- } +- +- if (info->xmit_cnt < WAKEUP_CHARS) { +- if (info->port.tty) +- tty_wakeup(info->port.tty); +- +-#ifdef SERIAL_DEBUG_INTR +- printk("THRE..."); +-#endif +- +- if (info->xmit_cnt <= 0) { +- info->IER &= ~UART_IER_THRI; +- serial_out(info, UART_ESI_CMD1, +- ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- } +- } +- +- release_pio_buffer(pio_buf); +-} +- +-/* Caller must hold info->lock */ +-static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes) +-{ +- dma_bytes = num_bytes; +- +- if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) { +- memcpy(dma_buffer, &(info->xmit_buf[info->xmit_tail]), +- dma_bytes); +- } else { +- int i = ESP_XMIT_SIZE - info->xmit_tail; +- memcpy(dma_buffer, &(info->xmit_buf[info->xmit_tail]), +- i); +- memcpy(&(dma_buffer[i]), info->xmit_buf, dma_bytes - i); +- } +- +- info->xmit_cnt -= dma_bytes; +- info->xmit_tail = (info->xmit_tail + dma_bytes) & (ESP_XMIT_SIZE - 1); +- +- if (info->xmit_cnt < WAKEUP_CHARS) { +- if (info->port.tty) +- tty_wakeup(info->port.tty); +- +-#ifdef SERIAL_DEBUG_INTR +- printk("THRE..."); +-#endif +- +- if (info->xmit_cnt <= 0) { +- info->IER &= ~UART_IER_THRI; +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- } +- } +- +- info->stat_flags |= ESP_STAT_DMA_TX; +- +- program_isa_dma(dma, DMA_MODE_WRITE, isa_virt_to_bus(dma_buffer), +- dma_bytes); +- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX); +-} +- +-static inline void transmit_chars_dma_done(struct esp_struct *info) +-{ +- int num_bytes; +- unsigned long flags; +- +- flags = claim_dma_lock(); +- disable_dma(dma); +- clear_dma_ff(dma); +- +- num_bytes = dma_bytes - get_dma_residue(dma); +- info->icount.tx += dma_bytes; +- release_dma_lock(flags); +- +- if (dma_bytes != num_bytes) { +- dma_bytes -= num_bytes; +- memmove(dma_buffer, dma_buffer + num_bytes, dma_bytes); +- +- program_isa_dma(dma, DMA_MODE_WRITE, +- isa_virt_to_bus(dma_buffer), dma_bytes); +- +- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX); +- } else { +- dma_bytes = 0; +- info->stat_flags &= ~ESP_STAT_DMA_TX; +- } +-} +- +-static void check_modem_status(struct esp_struct *info) +-{ +- int status; +- +- serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); +- status = serial_in(info, UART_ESI_STAT2); +- +- if (status & UART_MSR_ANY_DELTA) { +- /* update input line counters */ +- if (status & UART_MSR_TERI) +- info->icount.rng++; +- if (status & UART_MSR_DDSR) +- info->icount.dsr++; +- if (status & UART_MSR_DDCD) +- info->icount.dcd++; +- if (status & UART_MSR_DCTS) +- info->icount.cts++; +- wake_up_interruptible(&info->port.delta_msr_wait); +- } +- +- if ((info->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { +-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) +- printk("ttys%d CD now %s...", info->line, +- (status & UART_MSR_DCD) ? "on" : "off"); +-#endif +- if (status & UART_MSR_DCD) +- wake_up_interruptible(&info->port.open_wait); +- else { +-#ifdef SERIAL_DEBUG_OPEN +- printk("scheduling hangup..."); +-#endif +- tty_hangup(info->port.tty); +- } +- } +-} +- +-/* +- * This is the serial driver's interrupt routine +- */ +-static irqreturn_t rs_interrupt_single(int irq, void *dev_id) +-{ +- struct esp_struct *info; +- unsigned err_status; +- unsigned int scratch; +- +-#ifdef SERIAL_DEBUG_INTR +- printk("rs_interrupt_single(%d)...", irq); +-#endif +- info = (struct esp_struct *)dev_id; +- err_status = 0; +- scratch = serial_in(info, UART_ESI_SID); +- +- spin_lock(&info->lock); +- +- if (!info->port.tty) { +- spin_unlock(&info->lock); +- return IRQ_NONE; +- } +- +- if (scratch & 0x04) { /* error */ +- serial_out(info, UART_ESI_CMD1, ESI_GET_ERR_STAT); +- err_status = serial_in(info, UART_ESI_STAT1); +- serial_in(info, UART_ESI_STAT2); +- +- if (err_status & 0x01) +- info->stat_flags |= ESP_STAT_RX_TIMEOUT; +- +- if (err_status & 0x20) /* UART status */ +- check_modem_status(info); +- +- if (err_status & 0x80) /* Start break */ +- wake_up_interruptible(&info->break_wait); +- } +- +- if ((scratch & 0x88) || /* DMA completed or timed out */ +- (err_status & 0x1c) /* receive error */) { +- if (info->stat_flags & ESP_STAT_DMA_RX) +- receive_chars_dma_done(info, err_status); +- else if (info->stat_flags & ESP_STAT_DMA_TX) +- transmit_chars_dma_done(info); +- } +- +- if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) && +- ((scratch & 0x01) || (info->stat_flags & ESP_STAT_RX_TIMEOUT)) && +- (info->IER & UART_IER_RDI)) { +- int num_bytes; +- +- serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); +- serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL); +- num_bytes = serial_in(info, UART_ESI_STAT1) << 8; +- num_bytes |= serial_in(info, UART_ESI_STAT2); +- +- num_bytes = tty_buffer_request_room(info->port.tty, num_bytes); +- +- if (num_bytes) { +- if (dma_bytes || +- (info->stat_flags & ESP_STAT_USE_PIO) || +- (num_bytes <= info->config.pio_threshold)) +- receive_chars_pio(info, num_bytes); +- else +- receive_chars_dma(info, num_bytes); +- } +- } +- +- if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) && +- (scratch & 0x02) && (info->IER & UART_IER_THRI)) { +- if ((info->xmit_cnt <= 0) || info->port.tty->stopped) { +- info->IER &= ~UART_IER_THRI; +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- } else { +- int num_bytes; +- +- serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); +- serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); +- num_bytes = serial_in(info, UART_ESI_STAT1) << 8; +- num_bytes |= serial_in(info, UART_ESI_STAT2); +- +- if (num_bytes > info->xmit_cnt) +- num_bytes = info->xmit_cnt; +- +- if (num_bytes) { +- if (dma_bytes || +- (info->stat_flags & ESP_STAT_USE_PIO) || +- (num_bytes <= info->config.pio_threshold)) +- transmit_chars_pio(info, num_bytes); +- else +- transmit_chars_dma(info, num_bytes); +- } +- } +- } +- +- info->last_active = jiffies; +- +-#ifdef SERIAL_DEBUG_INTR +- printk("end.\n"); +-#endif +- spin_unlock(&info->lock); +- return IRQ_HANDLED; +-} +- +-/* +- * ------------------------------------------------------------------- +- * Here ends the serial interrupt routines. +- * ------------------------------------------------------------------- +- */ +- +-/* +- * --------------------------------------------------------------- +- * Low level utility subroutines for the serial driver: routines to +- * figure out the appropriate timeout for an interrupt chain, routines +- * to initialize and startup a serial port, and routines to shutdown a +- * serial port. Useful stuff like that. +- * +- * Caller should hold lock +- * --------------------------------------------------------------- +- */ +- +-static void esp_basic_init(struct esp_struct *info) +-{ +- /* put ESPC in enhanced mode */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_MODE); +- +- if (info->stat_flags & ESP_STAT_NEVER_DMA) +- serial_out(info, UART_ESI_CMD2, 0x01); +- else +- serial_out(info, UART_ESI_CMD2, 0x31); +- +- /* disable interrupts for now */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, 0x00); +- +- /* set interrupt and DMA channel */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_IRQ); +- +- if (info->stat_flags & ESP_STAT_NEVER_DMA) +- serial_out(info, UART_ESI_CMD2, 0x01); +- else +- serial_out(info, UART_ESI_CMD2, (dma << 4) | 0x01); +- +- serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ); +- +- if (info->line % 8) /* secondary port */ +- serial_out(info, UART_ESI_CMD2, 0x0d); /* shared */ +- else if (info->irq == 9) +- serial_out(info, UART_ESI_CMD2, 0x02); +- else +- serial_out(info, UART_ESI_CMD2, info->irq); +- +- /* set error status mask (check this) */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_ERR_MASK); +- +- if (info->stat_flags & ESP_STAT_NEVER_DMA) +- serial_out(info, UART_ESI_CMD2, 0xa1); +- else +- serial_out(info, UART_ESI_CMD2, 0xbd); +- +- serial_out(info, UART_ESI_CMD2, 0x00); +- +- /* set DMA timeout */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_DMA_TMOUT); +- serial_out(info, UART_ESI_CMD2, 0xff); +- +- /* set FIFO trigger levels */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER); +- serial_out(info, UART_ESI_CMD2, info->config.rx_trigger >> 8); +- serial_out(info, UART_ESI_CMD2, info->config.rx_trigger); +- serial_out(info, UART_ESI_CMD2, info->config.tx_trigger >> 8); +- serial_out(info, UART_ESI_CMD2, info->config.tx_trigger); +- +- /* Set clock scaling and wait states */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_PRESCALAR); +- serial_out(info, UART_ESI_CMD2, 0x04 | ESPC_SCALE); +- +- /* set reinterrupt pacing */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_REINTR); +- serial_out(info, UART_ESI_CMD2, 0xff); +-} +- +-static int startup(struct esp_struct *info) +-{ +- unsigned long flags; +- int retval = 0; +- unsigned int num_chars; +- +- spin_lock_irqsave(&info->lock, flags); +- +- if (info->port.flags & ASYNC_INITIALIZED) +- goto out; +- +- if (!info->xmit_buf) { +- info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_ATOMIC); +- retval = -ENOMEM; +- if (!info->xmit_buf) +- goto out; +- } +- +-#ifdef SERIAL_DEBUG_OPEN +- printk(KERN_DEBUG "starting up ttys%d (irq %d)...", +- info->line, info->irq); +-#endif +- +- /* Flush the RX buffer. Using the ESI flush command may cause */ +- /* wild interrupts, so read all the data instead. */ +- +- serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); +- serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL); +- num_chars = serial_in(info, UART_ESI_STAT1) << 8; +- num_chars |= serial_in(info, UART_ESI_STAT2); +- +- while (num_chars > 1) { +- inw(info->io_port + UART_ESI_RX); +- num_chars -= 2; +- } +- +- if (num_chars) +- serial_in(info, UART_ESI_RX); +- +- /* set receive character timeout */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); +- serial_out(info, UART_ESI_CMD2, info->config.rx_timeout); +- +- /* clear all flags except the "never DMA" flag */ +- info->stat_flags &= ESP_STAT_NEVER_DMA; +- +- if (info->stat_flags & ESP_STAT_NEVER_DMA) +- info->stat_flags |= ESP_STAT_USE_PIO; +- +- spin_unlock_irqrestore(&info->lock, flags); +- +- /* +- * Allocate the IRQ +- */ +- +- retval = request_irq(info->irq, rs_interrupt_single, IRQF_SHARED, +- "esp serial", info); +- +- if (retval) { +- if (capable(CAP_SYS_ADMIN)) { +- if (info->port.tty) +- set_bit(TTY_IO_ERROR, +- &info->port.tty->flags); +- retval = 0; +- } +- goto out_unlocked; +- } +- +- if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) { +- dma_buffer = (char *)__get_dma_pages( +- GFP_KERNEL, get_order(DMA_BUFFER_SZ)); +- +- /* use PIO mode if DMA buf/chan cannot be allocated */ +- if (!dma_buffer) +- info->stat_flags |= ESP_STAT_USE_PIO; +- else if (request_dma(dma, "esp serial")) { +- free_pages((unsigned long)dma_buffer, +- get_order(DMA_BUFFER_SZ)); +- dma_buffer = NULL; +- info->stat_flags |= ESP_STAT_USE_PIO; +- } +- +- } +- +- info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; +- +- spin_lock_irqsave(&info->lock, flags); +- serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); +- serial_out(info, UART_ESI_CMD2, UART_MCR); +- serial_out(info, UART_ESI_CMD2, info->MCR); +- +- /* +- * Finally, enable interrupts +- */ +- /* info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; */ +- info->IER = UART_IER_RLSI | UART_IER_RDI | UART_IER_DMA_TMOUT | +- UART_IER_DMA_TC; +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- +- if (info->port.tty) +- clear_bit(TTY_IO_ERROR, &info->port.tty->flags); +- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; +- spin_unlock_irqrestore(&info->lock, flags); +- +- /* +- * Set up the tty->alt_speed kludge +- */ +- if (info->port.tty) { +- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) +- info->port.tty->alt_speed = 57600; +- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) +- info->port.tty->alt_speed = 115200; +- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) +- info->port.tty->alt_speed = 230400; +- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) +- info->port.tty->alt_speed = 460800; +- } +- +- /* +- * set the speed of the serial port +- */ +- change_speed(info); +- info->port.flags |= ASYNC_INITIALIZED; +- return 0; +- +-out: +- spin_unlock_irqrestore(&info->lock, flags); +-out_unlocked: +- return retval; +-} +- +-/* +- * This routine will shutdown a serial port; interrupts are disabled, and +- * DTR is dropped if the hangup on close termio flag is on. +- */ +-static void shutdown(struct esp_struct *info) +-{ +- unsigned long flags, f; +- +- if (!(info->port.flags & ASYNC_INITIALIZED)) +- return; +- +-#ifdef SERIAL_DEBUG_OPEN +- printk("Shutting down serial port %d (irq %d)....", info->line, +- info->irq); +-#endif +- +- spin_lock_irqsave(&info->lock, flags); +- /* +- * clear delta_msr_wait queue to avoid mem leaks: we may free the irq +- * here so the queue might never be waken up +- */ +- wake_up_interruptible(&info->port.delta_msr_wait); +- wake_up_interruptible(&info->break_wait); +- +- /* stop a DMA transfer on the port being closed */ +- /* DMA lock is higher priority always */ +- if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) { +- f = claim_dma_lock(); +- disable_dma(dma); +- clear_dma_ff(dma); +- release_dma_lock(f); +- +- dma_bytes = 0; +- } +- +- /* +- * Free the IRQ +- */ +- free_irq(info->irq, info); +- +- if (dma_buffer) { +- struct esp_struct *current_port = ports; +- +- while (current_port) { +- if ((current_port != info) && +- (current_port->port.flags & ASYNC_INITIALIZED)) +- break; +- +- current_port = current_port->next_port; +- } +- +- if (!current_port) { +- free_dma(dma); +- free_pages((unsigned long)dma_buffer, +- get_order(DMA_BUFFER_SZ)); +- dma_buffer = NULL; +- } +- } +- +- if (info->xmit_buf) { +- free_page((unsigned long) info->xmit_buf); +- info->xmit_buf = NULL; +- } +- +- info->IER = 0; +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, 0x00); +- +- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) +- info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); +- +- info->MCR &= ~UART_MCR_OUT2; +- serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); +- serial_out(info, UART_ESI_CMD2, UART_MCR); +- serial_out(info, UART_ESI_CMD2, info->MCR); +- +- if (info->port.tty) +- set_bit(TTY_IO_ERROR, &info->port.tty->flags); +- +- info->port.flags &= ~ASYNC_INITIALIZED; +- spin_unlock_irqrestore(&info->lock, flags); +-} +- +-/* +- * This routine is called to set the UART divisor registers to match +- * the specified baud rate for a serial port. +- */ +-static void change_speed(struct esp_struct *info) +-{ +- unsigned short port; +- int quot = 0; +- unsigned cflag, cval; +- int baud, bits; +- unsigned char flow1 = 0, flow2 = 0; +- unsigned long flags; +- +- if (!info->port.tty || !info->port.tty->termios) +- return; +- cflag = info->port.tty->termios->c_cflag; +- port = info->io_port; +- +- /* byte size and parity */ +- switch (cflag & CSIZE) { +- case CS5: cval = 0x00; bits = 7; break; +- case CS6: cval = 0x01; bits = 8; break; +- case CS7: cval = 0x02; bits = 9; break; +- case CS8: cval = 0x03; bits = 10; break; +- default: cval = 0x00; bits = 7; break; +- } +- if (cflag & CSTOPB) { +- cval |= 0x04; +- bits++; +- } +- if (cflag & PARENB) { +- cval |= UART_LCR_PARITY; +- bits++; +- } +- if (!(cflag & PARODD)) +- cval |= UART_LCR_EPAR; +-#ifdef CMSPAR +- if (cflag & CMSPAR) +- cval |= UART_LCR_SPAR; +-#endif +- baud = tty_get_baud_rate(info->port.tty); +- if (baud == 38400 && +- ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) +- quot = info->custom_divisor; +- else { +- if (baud == 134) /* Special case since 134 is really 134.5 */ +- quot = (2*BASE_BAUD / 269); +- else if (baud) +- quot = BASE_BAUD / baud; +- } +- /* If the quotient is ever zero, default to 9600 bps */ +- if (!quot) +- quot = BASE_BAUD / 9600; +- +- if (baud) { +- /* Actual rate */ +- baud = BASE_BAUD/quot; +- tty_encode_baud_rate(info->port.tty, baud, baud); +- } +- info->timeout = ((1024 * HZ * bits * quot) / BASE_BAUD) + (HZ / 50); +- +- /* CTS flow control flag and modem status interrupts */ +- /* info->IER &= ~UART_IER_MSI; */ +- if (cflag & CRTSCTS) { +- info->port.flags |= ASYNC_CTS_FLOW; +- /* info->IER |= UART_IER_MSI; */ +- flow1 = 0x04; +- flow2 = 0x10; +- } else +- info->port.flags &= ~ASYNC_CTS_FLOW; +- if (cflag & CLOCAL) +- info->port.flags &= ~ASYNC_CHECK_CD; +- else +- info->port.flags |= ASYNC_CHECK_CD; +- +- /* +- * Set up parity check flag +- */ +- info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; +- if (I_INPCK(info->port.tty)) +- info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; +- if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) +- info->read_status_mask |= UART_LSR_BI; +- +- info->ignore_status_mask = 0; +-#if 0 +- /* This should be safe, but for some broken bits of hardware... */ +- if (I_IGNPAR(info->port.tty)) { +- info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; +- info->read_status_mask |= UART_LSR_PE | UART_LSR_FE; +- } +-#endif +- if (I_IGNBRK(info->port.tty)) { +- info->ignore_status_mask |= UART_LSR_BI; +- info->read_status_mask |= UART_LSR_BI; +- /* +- * If we're ignore parity and break indicators, ignore +- * overruns too. (For real raw support). +- */ +- if (I_IGNPAR(info->port.tty)) { +- info->ignore_status_mask |= UART_LSR_OE | \ +- UART_LSR_PE | UART_LSR_FE; +- info->read_status_mask |= UART_LSR_OE | \ +- UART_LSR_PE | UART_LSR_FE; +- } +- } +- +- if (I_IXOFF(info->port.tty)) +- flow1 |= 0x81; +- +- spin_lock_irqsave(&info->lock, flags); +- /* set baud */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_BAUD); +- serial_out(info, UART_ESI_CMD2, quot >> 8); +- serial_out(info, UART_ESI_CMD2, quot & 0xff); +- +- /* set data bits, parity, etc. */ +- serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); +- serial_out(info, UART_ESI_CMD2, UART_LCR); +- serial_out(info, UART_ESI_CMD2, cval); +- +- /* Enable flow control */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_CNTL); +- serial_out(info, UART_ESI_CMD2, flow1); +- serial_out(info, UART_ESI_CMD2, flow2); +- +- /* set flow control characters (XON/XOFF only) */ +- if (I_IXOFF(info->port.tty)) { +- serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_CHARS); +- serial_out(info, UART_ESI_CMD2, START_CHAR(info->port.tty)); +- serial_out(info, UART_ESI_CMD2, STOP_CHAR(info->port.tty)); +- serial_out(info, UART_ESI_CMD2, 0x10); +- serial_out(info, UART_ESI_CMD2, 0x21); +- switch (cflag & CSIZE) { +- case CS5: +- serial_out(info, UART_ESI_CMD2, 0x1f); +- break; +- case CS6: +- serial_out(info, UART_ESI_CMD2, 0x3f); +- break; +- case CS7: +- case CS8: +- serial_out(info, UART_ESI_CMD2, 0x7f); +- break; +- default: +- serial_out(info, UART_ESI_CMD2, 0xff); +- break; +- } +- } +- +- /* Set high/low water */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL); +- serial_out(info, UART_ESI_CMD2, info->config.flow_off >> 8); +- serial_out(info, UART_ESI_CMD2, info->config.flow_off); +- serial_out(info, UART_ESI_CMD2, info->config.flow_on >> 8); +- serial_out(info, UART_ESI_CMD2, info->config.flow_on); +- +- spin_unlock_irqrestore(&info->lock, flags); +-} +- +-static int rs_put_char(struct tty_struct *tty, unsigned char ch) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +- int ret = 0; +- +- if (serial_paranoia_check(info, tty->name, "rs_put_char")) +- return 0; +- +- if (!info->xmit_buf) +- return 0; +- +- spin_lock_irqsave(&info->lock, flags); +- if (info->xmit_cnt < ESP_XMIT_SIZE - 1) { +- info->xmit_buf[info->xmit_head++] = ch; +- info->xmit_head &= ESP_XMIT_SIZE-1; +- info->xmit_cnt++; +- ret = 1; +- } +- spin_unlock_irqrestore(&info->lock, flags); +- return ret; +-} +- +-static void rs_flush_chars(struct tty_struct *tty) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +- +- if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) +- return; +- +- spin_lock_irqsave(&info->lock, flags); +- +- if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) +- goto out; +- +- if (!(info->IER & UART_IER_THRI)) { +- info->IER |= UART_IER_THRI; +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- } +-out: +- spin_unlock_irqrestore(&info->lock, flags); +-} +- +-static int rs_write(struct tty_struct *tty, +- const unsigned char *buf, int count) +-{ +- int c, t, ret = 0; +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +- +- if (serial_paranoia_check(info, tty->name, "rs_write")) +- return 0; +- +- if (!info->xmit_buf) +- return 0; +- +- while (1) { +- /* Thanks to R. Wolff for suggesting how to do this with */ +- /* interrupts enabled */ +- +- c = count; +- t = ESP_XMIT_SIZE - info->xmit_cnt - 1; +- +- if (t < c) +- c = t; +- +- t = ESP_XMIT_SIZE - info->xmit_head; +- +- if (t < c) +- c = t; +- +- if (c <= 0) +- break; +- +- memcpy(info->xmit_buf + info->xmit_head, buf, c); +- +- info->xmit_head = (info->xmit_head + c) & (ESP_XMIT_SIZE-1); +- info->xmit_cnt += c; +- buf += c; +- count -= c; +- ret += c; +- } +- +- spin_lock_irqsave(&info->lock, flags); +- +- if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) { +- info->IER |= UART_IER_THRI; +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- } +- +- spin_unlock_irqrestore(&info->lock, flags); +- return ret; +-} +- +-static int rs_write_room(struct tty_struct *tty) +-{ +- struct esp_struct *info = tty->driver_data; +- int ret; +- unsigned long flags; +- +- if (serial_paranoia_check(info, tty->name, "rs_write_room")) +- return 0; +- +- spin_lock_irqsave(&info->lock, flags); +- +- ret = ESP_XMIT_SIZE - info->xmit_cnt - 1; +- if (ret < 0) +- ret = 0; +- spin_unlock_irqrestore(&info->lock, flags); +- return ret; +-} +- +-static int rs_chars_in_buffer(struct tty_struct *tty) +-{ +- struct esp_struct *info = tty->driver_data; +- +- if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) +- return 0; +- return info->xmit_cnt; +-} +- +-static void rs_flush_buffer(struct tty_struct *tty) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +- +- if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) +- return; +- spin_lock_irqsave(&info->lock, flags); +- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; +- spin_unlock_irqrestore(&info->lock, flags); +- tty_wakeup(tty); +-} +- +-/* +- * ------------------------------------------------------------ +- * rs_throttle() +- * +- * This routine is called by the upper-layer tty layer to signal that +- * incoming characters should be throttled. +- * ------------------------------------------------------------ +- */ +-static void rs_throttle(struct tty_struct *tty) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +-#ifdef SERIAL_DEBUG_THROTTLE +- char buf[64]; +- +- printk("throttle %s: %d....\n", tty_name(tty, buf), +- tty_chars_in_buffer(tty)); +-#endif +- +- if (serial_paranoia_check(info, tty->name, "rs_throttle")) +- return; +- +- spin_lock_irqsave(&info->lock, flags); +- info->IER &= ~UART_IER_RDI; +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); +- serial_out(info, UART_ESI_CMD2, 0x00); +- spin_unlock_irqrestore(&info->lock, flags); +-} +- +-static void rs_unthrottle(struct tty_struct *tty) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +-#ifdef SERIAL_DEBUG_THROTTLE +- char buf[64]; +- +- printk(KERN_DEBUG "unthrottle %s: %d....\n", tty_name(tty, buf), +- tty_chars_in_buffer(tty)); +-#endif +- +- if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) +- return; +- +- spin_lock_irqsave(&info->lock, flags); +- info->IER |= UART_IER_RDI; +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); +- serial_out(info, UART_ESI_CMD2, info->config.rx_timeout); +- spin_unlock_irqrestore(&info->lock, flags); +-} +- +-/* +- * ------------------------------------------------------------ +- * rs_ioctl() and friends +- * ------------------------------------------------------------ +- */ +- +-static int get_serial_info(struct esp_struct *info, +- struct serial_struct __user *retinfo) +-{ +- struct serial_struct tmp; +- +- lock_kernel(); +- memset(&tmp, 0, sizeof(tmp)); +- tmp.type = PORT_16550A; +- tmp.line = info->line; +- tmp.port = info->io_port; +- tmp.irq = info->irq; +- tmp.flags = info->port.flags; +- tmp.xmit_fifo_size = 1024; +- tmp.baud_base = BASE_BAUD; +- tmp.close_delay = info->close_delay; +- tmp.closing_wait = info->closing_wait; +- tmp.custom_divisor = info->custom_divisor; +- tmp.hub6 = 0; +- unlock_kernel(); +- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) +- return -EFAULT; +- return 0; +-} +- +-static int get_esp_config(struct esp_struct *info, +- struct hayes_esp_config __user *retinfo) +-{ +- struct hayes_esp_config tmp; +- +- if (!retinfo) +- return -EFAULT; +- +- memset(&tmp, 0, sizeof(tmp)); +- lock_kernel(); +- tmp.rx_timeout = info->config.rx_timeout; +- tmp.rx_trigger = info->config.rx_trigger; +- tmp.tx_trigger = info->config.tx_trigger; +- tmp.flow_off = info->config.flow_off; +- tmp.flow_on = info->config.flow_on; +- tmp.pio_threshold = info->config.pio_threshold; +- tmp.dma_channel = (info->stat_flags & ESP_STAT_NEVER_DMA ? 0 : dma); +- unlock_kernel(); +- +- return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; +-} +- +-static int set_serial_info(struct esp_struct *info, +- struct serial_struct __user *new_info) +-{ +- struct serial_struct new_serial; +- struct esp_struct old_info; +- unsigned int change_irq; +- int retval = 0; +- struct esp_struct *current_async; +- +- if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) +- return -EFAULT; +- old_info = *info; +- +- if ((new_serial.type != PORT_16550A) || +- (new_serial.hub6) || +- (info->io_port != new_serial.port) || +- (new_serial.baud_base != BASE_BAUD) || +- (new_serial.irq > 15) || +- (new_serial.irq < 2) || +- (new_serial.irq == 6) || +- (new_serial.irq == 8) || +- (new_serial.irq == 13)) +- return -EINVAL; +- +- change_irq = new_serial.irq != info->irq; +- +- if (change_irq && (info->line % 8)) +- return -EINVAL; +- +- if (!capable(CAP_SYS_ADMIN)) { +- if (change_irq || +- (new_serial.close_delay != info->close_delay) || +- ((new_serial.flags & ~ASYNC_USR_MASK) != +- (info->port.flags & ~ASYNC_USR_MASK))) +- return -EPERM; +- info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) | +- (new_serial.flags & ASYNC_USR_MASK)); +- info->custom_divisor = new_serial.custom_divisor; +- } else { +- if (new_serial.irq == 2) +- new_serial.irq = 9; +- +- if (change_irq) { +- current_async = ports; +- +- while (current_async) { +- if ((current_async->line >= info->line) && +- (current_async->line < (info->line + 8))) { +- if (current_async == info) { +- if (current_async->port.count > 1) +- return -EBUSY; +- } else if (current_async->port.count) +- return -EBUSY; +- } +- +- current_async = current_async->next_port; +- } +- } +- +- /* +- * OK, past this point, all the error checking has been done. +- * At this point, we start making changes..... +- */ +- +- info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) | +- (new_serial.flags & ASYNC_FLAGS)); +- info->custom_divisor = new_serial.custom_divisor; +- info->close_delay = new_serial.close_delay * HZ/100; +- info->closing_wait = new_serial.closing_wait * HZ/100; +- +- if (change_irq) { +- /* +- * We need to shutdown the serial port at the old +- * port/irq combination. +- */ +- shutdown(info); +- +- current_async = ports; +- +- while (current_async) { +- if ((current_async->line >= info->line) && +- (current_async->line < (info->line + 8))) +- current_async->irq = new_serial.irq; +- +- current_async = current_async->next_port; +- } +- +- serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ); +- if (info->irq == 9) +- serial_out(info, UART_ESI_CMD2, 0x02); +- else +- serial_out(info, UART_ESI_CMD2, info->irq); +- } +- } +- +- if (info->port.flags & ASYNC_INITIALIZED) { +- if (((old_info.port.flags & ASYNC_SPD_MASK) != +- (info->port.flags & ASYNC_SPD_MASK)) || +- (old_info.custom_divisor != info->custom_divisor)) { +- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) +- info->port.tty->alt_speed = 57600; +- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) +- info->port.tty->alt_speed = 115200; +- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) +- info->port.tty->alt_speed = 230400; +- if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) +- info->port.tty->alt_speed = 460800; +- change_speed(info); +- } +- } else +- retval = startup(info); +- +- return retval; +-} +- +-static int set_esp_config(struct esp_struct *info, +- struct hayes_esp_config __user *new_info) +-{ +- struct hayes_esp_config new_config; +- unsigned int change_dma; +- int retval = 0; +- struct esp_struct *current_async; +- unsigned long flags; +- +- /* Perhaps a non-sysadmin user should be able to do some of these */ +- /* operations. I haven't decided yet. */ +- +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; +- +- if (copy_from_user(&new_config, new_info, sizeof(new_config))) +- return -EFAULT; +- +- if ((new_config.flow_on >= new_config.flow_off) || +- (new_config.rx_trigger < 1) || +- (new_config.tx_trigger < 1) || +- (new_config.flow_off < 1) || +- (new_config.flow_on < 1) || +- (new_config.rx_trigger > 1023) || +- (new_config.tx_trigger > 1023) || +- (new_config.flow_off > 1023) || +- (new_config.flow_on > 1023) || +- (new_config.pio_threshold < 0) || +- (new_config.pio_threshold > 1024)) +- return -EINVAL; +- +- if ((new_config.dma_channel != 1) && (new_config.dma_channel != 3)) +- new_config.dma_channel = 0; +- +- if (info->stat_flags & ESP_STAT_NEVER_DMA) +- change_dma = new_config.dma_channel; +- else +- change_dma = (new_config.dma_channel != dma); +- +- if (change_dma) { +- if (new_config.dma_channel) { +- /* PIO mode to DMA mode transition OR */ +- /* change current DMA channel */ +- current_async = ports; +- +- while (current_async) { +- if (current_async == info) { +- if (current_async->port.count > 1) +- return -EBUSY; +- } else if (current_async->port.count) +- return -EBUSY; +- +- current_async = current_async->next_port; +- } +- +- shutdown(info); +- dma = new_config.dma_channel; +- info->stat_flags &= ~ESP_STAT_NEVER_DMA; +- +- /* all ports must use the same DMA channel */ +- +- spin_lock_irqsave(&info->lock, flags); +- current_async = ports; +- +- while (current_async) { +- esp_basic_init(current_async); +- current_async = current_async->next_port; +- } +- spin_unlock_irqrestore(&info->lock, flags); +- } else { +- /* DMA mode to PIO mode only */ +- if (info->port.count > 1) +- return -EBUSY; +- +- shutdown(info); +- spin_lock_irqsave(&info->lock, flags); +- info->stat_flags |= ESP_STAT_NEVER_DMA; +- esp_basic_init(info); +- spin_unlock_irqrestore(&info->lock, flags); +- } +- } +- +- info->config.pio_threshold = new_config.pio_threshold; +- +- if ((new_config.flow_off != info->config.flow_off) || +- (new_config.flow_on != info->config.flow_on)) { +- info->config.flow_off = new_config.flow_off; +- info->config.flow_on = new_config.flow_on; +- +- spin_lock_irqsave(&info->lock, flags); +- serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL); +- serial_out(info, UART_ESI_CMD2, new_config.flow_off >> 8); +- serial_out(info, UART_ESI_CMD2, new_config.flow_off); +- serial_out(info, UART_ESI_CMD2, new_config.flow_on >> 8); +- serial_out(info, UART_ESI_CMD2, new_config.flow_on); +- spin_unlock_irqrestore(&info->lock, flags); +- } +- +- if ((new_config.rx_trigger != info->config.rx_trigger) || +- (new_config.tx_trigger != info->config.tx_trigger)) { +- info->config.rx_trigger = new_config.rx_trigger; +- info->config.tx_trigger = new_config.tx_trigger; +- spin_lock_irqsave(&info->lock, flags); +- serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER); +- serial_out(info, UART_ESI_CMD2, +- new_config.rx_trigger >> 8); +- serial_out(info, UART_ESI_CMD2, new_config.rx_trigger); +- serial_out(info, UART_ESI_CMD2, +- new_config.tx_trigger >> 8); +- serial_out(info, UART_ESI_CMD2, new_config.tx_trigger); +- spin_unlock_irqrestore(&info->lock, flags); +- } +- +- if (new_config.rx_timeout != info->config.rx_timeout) { +- info->config.rx_timeout = new_config.rx_timeout; +- spin_lock_irqsave(&info->lock, flags); +- +- if (info->IER & UART_IER_RDI) { +- serial_out(info, UART_ESI_CMD1, +- ESI_SET_RX_TIMEOUT); +- serial_out(info, UART_ESI_CMD2, +- new_config.rx_timeout); +- } +- +- spin_unlock_irqrestore(&info->lock, flags); +- } +- +- if (!(info->port.flags & ASYNC_INITIALIZED)) +- retval = startup(info); +- +- return retval; +-} +- +-/* +- * get_lsr_info - get line status register info +- * +- * Purpose: Let user call ioctl() to get info when the UART physically +- * is emptied. On bus types like RS485, the transmitter must +- * release the bus after transmitting. This must be done when +- * the transmit shift register is empty, not be done when the +- * transmit holding register is empty. This functionality +- * allows an RS485 driver to be written in user space. +- */ +-static int get_lsr_info(struct esp_struct *info, unsigned int __user *value) +-{ +- unsigned char status; +- unsigned int result; +- unsigned long flags; +- +- spin_lock_irqsave(&info->lock, flags); +- serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); +- status = serial_in(info, UART_ESI_STAT1); +- spin_unlock_irqrestore(&info->lock, flags); +- result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); +- return put_user(result, value); +-} +- +- +-static int esp_tiocmget(struct tty_struct *tty, struct file *file) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned char control, status; +- unsigned long flags; +- +- if (serial_paranoia_check(info, tty->name, __func__)) +- return -ENODEV; +- if (tty->flags & (1 << TTY_IO_ERROR)) +- return -EIO; +- +- control = info->MCR; +- +- spin_lock_irqsave(&info->lock, flags); +- serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); +- status = serial_in(info, UART_ESI_STAT2); +- spin_unlock_irqrestore(&info->lock, flags); +- +- return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) +- | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) +- | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) +- | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) +- | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) +- | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); +-} +- +-static int esp_tiocmset(struct tty_struct *tty, struct file *file, +- unsigned int set, unsigned int clear) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +- +- if (serial_paranoia_check(info, tty->name, __func__)) +- return -ENODEV; +- if (tty->flags & (1 << TTY_IO_ERROR)) +- return -EIO; +- +- spin_lock_irqsave(&info->lock, flags); +- +- if (set & TIOCM_RTS) +- info->MCR |= UART_MCR_RTS; +- if (set & TIOCM_DTR) +- info->MCR |= UART_MCR_DTR; +- +- if (clear & TIOCM_RTS) +- info->MCR &= ~UART_MCR_RTS; +- if (clear & TIOCM_DTR) +- info->MCR &= ~UART_MCR_DTR; +- +- serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); +- serial_out(info, UART_ESI_CMD2, UART_MCR); +- serial_out(info, UART_ESI_CMD2, info->MCR); +- +- spin_unlock_irqrestore(&info->lock, flags); +- return 0; +-} +- +-/* +- * rs_break() --- routine which turns the break handling on or off +- */ +-static int esp_break(struct tty_struct *tty, int break_state) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +- +- if (serial_paranoia_check(info, tty->name, "esp_break")) +- return -EINVAL; +- +- if (break_state == -1) { +- spin_lock_irqsave(&info->lock, flags); +- serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK); +- serial_out(info, UART_ESI_CMD2, 0x01); +- spin_unlock_irqrestore(&info->lock, flags); +- +- /* FIXME - new style wait needed here */ +- interruptible_sleep_on(&info->break_wait); +- } else { +- spin_lock_irqsave(&info->lock, flags); +- serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK); +- serial_out(info, UART_ESI_CMD2, 0x00); +- spin_unlock_irqrestore(&info->lock, flags); +- } +- return 0; +-} +- +-static int rs_ioctl(struct tty_struct *tty, struct file *file, +- unsigned int cmd, unsigned long arg) +-{ +- struct esp_struct *info = tty->driver_data; +- struct async_icount cprev, cnow; /* kernel counter temps */ +- struct serial_icounter_struct __user *p_cuser; /* user space */ +- void __user *argp = (void __user *)arg; +- unsigned long flags; +- int ret; +- +- if (serial_paranoia_check(info, tty->name, "rs_ioctl")) +- return -ENODEV; +- +- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && +- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && +- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) && +- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT) && +- (cmd != TIOCGHAYESESP) && (cmd != TIOCSHAYESESP)) { +- if (tty->flags & (1 << TTY_IO_ERROR)) +- return -EIO; +- } +- +- switch (cmd) { +- case TIOCGSERIAL: +- return get_serial_info(info, argp); +- case TIOCSSERIAL: +- lock_kernel(); +- ret = set_serial_info(info, argp); +- unlock_kernel(); +- return ret; +- case TIOCSERGWILD: +- return put_user(0L, (unsigned long __user *)argp); +- case TIOCSERGETLSR: /* Get line status register */ +- return get_lsr_info(info, argp); +- case TIOCSERSWILD: +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; +- return 0; +- /* +- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change +- * - mask passed in arg for lines of interest +- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) +- * Caller should use TIOCGICOUNT to see which one it was +- */ +- case TIOCMIWAIT: +- spin_lock_irqsave(&info->lock, flags); +- cprev = info->icount; /* note the counters on entry */ +- spin_unlock_irqrestore(&info->lock, flags); +- while (1) { +- /* FIXME: convert to new style wakeup */ +- interruptible_sleep_on(&info->port.delta_msr_wait); +- /* see if a signal did it */ +- if (signal_pending(current)) +- return -ERESTARTSYS; +- spin_lock_irqsave(&info->lock, flags); +- cnow = info->icount; /* atomic copy */ +- spin_unlock_irqrestore(&info->lock, flags); +- if (cnow.rng == cprev.rng && +- cnow.dsr == cprev.dsr && +- cnow.dcd == cprev.dcd && +- cnow.cts == cprev.cts) +- return -EIO; /* no change => error */ +- if (((arg & TIOCM_RNG) && +- (cnow.rng != cprev.rng)) || +- ((arg & TIOCM_DSR) && +- (cnow.dsr != cprev.dsr)) || +- ((arg & TIOCM_CD) && +- (cnow.dcd != cprev.dcd)) || +- ((arg & TIOCM_CTS) && +- (cnow.cts != cprev.cts))) { +- return 0; +- } +- cprev = cnow; +- } +- /* NOTREACHED */ +- /* +- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) +- * Return: write counters to the user passed counter struct +- * NB: both 1->0 and 0->1 transitions are counted except for +- * RI where only 0->1 is counted. +- */ +- case TIOCGICOUNT: +- spin_lock_irqsave(&info->lock, flags); +- cnow = info->icount; +- spin_unlock_irqrestore(&info->lock, flags); +- p_cuser = argp; +- if (put_user(cnow.cts, &p_cuser->cts) || +- put_user(cnow.dsr, &p_cuser->dsr) || +- put_user(cnow.rng, &p_cuser->rng) || +- put_user(cnow.dcd, &p_cuser->dcd)) +- return -EFAULT; +- return 0; +- case TIOCGHAYESESP: +- return get_esp_config(info, argp); +- case TIOCSHAYESESP: +- lock_kernel(); +- ret = set_esp_config(info, argp); +- unlock_kernel(); +- return ret; +- default: +- return -ENOIOCTLCMD; +- } +- return 0; +-} +- +-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +- +- change_speed(info); +- +- spin_lock_irqsave(&info->lock, flags); +- +- /* Handle transition to B0 status */ +- if ((old_termios->c_cflag & CBAUD) && +- !(tty->termios->c_cflag & CBAUD)) { +- info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); +- serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); +- serial_out(info, UART_ESI_CMD2, UART_MCR); +- serial_out(info, UART_ESI_CMD2, info->MCR); +- } +- +- /* Handle transition away from B0 status */ +- if (!(old_termios->c_cflag & CBAUD) && +- (tty->termios->c_cflag & CBAUD)) { +- info->MCR |= (UART_MCR_DTR | UART_MCR_RTS); +- serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); +- serial_out(info, UART_ESI_CMD2, UART_MCR); +- serial_out(info, UART_ESI_CMD2, info->MCR); +- } +- +- spin_unlock_irqrestore(&info->lock, flags); +- +- /* Handle turning of CRTSCTS */ +- if ((old_termios->c_cflag & CRTSCTS) && +- !(tty->termios->c_cflag & CRTSCTS)) { +- rs_start(tty); +- } +-} +- +-/* +- * ------------------------------------------------------------ +- * rs_close() +- * +- * This routine is called when the serial port gets closed. First, we +- * wait for the last remaining data to be sent. Then, we unlink its +- * async structure from the interrupt chain if necessary, and we free +- * that IRQ if nothing is left in the chain. +- * ------------------------------------------------------------ +- */ +-static void rs_close(struct tty_struct *tty, struct file *filp) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long flags; +- +- if (!info || serial_paranoia_check(info, tty->name, "rs_close")) +- return; +- +- spin_lock_irqsave(&info->lock, flags); +- +- if (tty_hung_up_p(filp)) { +- DBG_CNT("before DEC-hung"); +- goto out; +- } +- +-#ifdef SERIAL_DEBUG_OPEN +- printk(KERN_DEBUG "rs_close ttys%d, count = %d\n", +- info->line, info->port.count); +-#endif +- if (tty->count == 1 && info->port.count != 1) { +- /* +- * Uh, oh. tty->count is 1, which means that the tty +- * structure will be freed. Info->count should always +- * be one in these conditions. If it's greater than +- * one, we've got real problems, since it means the +- * serial port won't be shutdown. +- */ +- printk(KERN_DEBUG "rs_close: bad serial port count; tty->count is 1, info->port.count is %d\n", info->port.count); +- info->port.count = 1; +- } +- if (--info->port.count < 0) { +- printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", +- info->line, info->port.count); +- info->port.count = 0; +- } +- if (info->port.count) { +- DBG_CNT("before DEC-2"); +- goto out; +- } +- info->port.flags |= ASYNC_CLOSING; +- +- spin_unlock_irqrestore(&info->lock, flags); +- /* +- * Now we wait for the transmit buffer to clear; and we notify +- * the line discipline to only process XON/XOFF characters. +- */ +- tty->closing = 1; +- if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) +- tty_wait_until_sent(tty, info->closing_wait); +- /* +- * At this point we stop accepting input. To do this, we +- * disable the receive line status interrupts, and tell the +- * interrupt driver to stop checking the data ready bit in the +- * line status register. +- */ +- /* info->IER &= ~UART_IER_RLSI; */ +- info->IER &= ~UART_IER_RDI; +- info->read_status_mask &= ~UART_LSR_DR; +- if (info->port.flags & ASYNC_INITIALIZED) { +- +- spin_lock_irqsave(&info->lock, flags); +- serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); +- serial_out(info, UART_ESI_CMD2, info->IER); +- +- /* disable receive timeout */ +- serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); +- serial_out(info, UART_ESI_CMD2, 0x00); +- +- spin_unlock_irqrestore(&info->lock, flags); +- +- /* +- * Before we drop DTR, make sure the UART transmitter +- * has completely drained; this is especially +- * important if there is a transmit FIFO! +- */ +- rs_wait_until_sent(tty, info->timeout); +- } +- shutdown(info); +- rs_flush_buffer(tty); +- tty_ldisc_flush(tty); +- tty->closing = 0; +- info->port.tty = NULL; +- +- if (info->port.blocked_open) { +- if (info->close_delay) +- msleep_interruptible(jiffies_to_msecs(info->close_delay)); +- wake_up_interruptible(&info->port.open_wait); +- } +- info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); +- wake_up_interruptible(&info->port.close_wait); +- return; +- +-out: +- spin_unlock_irqrestore(&info->lock, flags); +-} +- +-static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +-{ +- struct esp_struct *info = tty->driver_data; +- unsigned long orig_jiffies, char_time; +- unsigned long flags; +- +- if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) +- return; +- +- orig_jiffies = jiffies; +- char_time = ((info->timeout - HZ / 50) / 1024) / 5; +- +- if (!char_time) +- char_time = 1; +- +- spin_lock_irqsave(&info->lock, flags); +- serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); +- serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); +- +- while ((serial_in(info, UART_ESI_STAT1) != 0x03) || +- (serial_in(info, UART_ESI_STAT2) != 0xff)) { +- +- spin_unlock_irqrestore(&info->lock, flags); +- msleep_interruptible(jiffies_to_msecs(char_time)); +- +- if (signal_pending(current)) +- return; +- +- if (timeout && time_after(jiffies, orig_jiffies + timeout)) +- return; +- +- spin_lock_irqsave(&info->lock, flags); +- serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); +- serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); +- } +- spin_unlock_irqrestore(&info->lock, flags); +- set_current_state(TASK_RUNNING); +-} +- +-/* +- * esp_hangup() --- called by tty_hangup() when a hangup is signaled. +- */ +-static void esp_hangup(struct tty_struct *tty) +-{ +- struct esp_struct *info = tty->driver_data; +- +- if (serial_paranoia_check(info, tty->name, "esp_hangup")) +- return; +- +- rs_flush_buffer(tty); +- shutdown(info); +- info->port.count = 0; +- info->port.flags &= ~ASYNC_NORMAL_ACTIVE; +- info->port.tty = NULL; +- wake_up_interruptible(&info->port.open_wait); +-} +- +-static int esp_carrier_raised(struct tty_port *port) +-{ +- struct esp_struct *info = container_of(port, struct esp_struct, port); +- serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); +- if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD) +- return 1; +- return 0; +-} +- +-/* +- * ------------------------------------------------------------ +- * esp_open() and friends +- * ------------------------------------------------------------ +- */ +-static int block_til_ready(struct tty_struct *tty, struct file *filp, +- struct esp_struct *info) +-{ +- DECLARE_WAITQUEUE(wait, current); +- int retval; +- int do_clocal = 0; +- unsigned long flags; +- int cd; +- struct tty_port *port = &info->port; +- +- /* +- * If the device is in the middle of being closed, then block +- * until it's done, and then try again. +- */ +- if (tty_hung_up_p(filp) || +- (port->flags & ASYNC_CLOSING)) { +- if (port->flags & ASYNC_CLOSING) +- interruptible_sleep_on(&port->close_wait); +-#ifdef SERIAL_DO_RESTART +- if (port->flags & ASYNC_HUP_NOTIFY) +- return -EAGAIN; +- else +- return -ERESTARTSYS; +-#else +- return -EAGAIN; +-#endif +- } +- +- /* +- * If non-blocking mode is set, or the port is not enabled, +- * then make the check up front and then exit. +- */ +- if ((filp->f_flags & O_NONBLOCK) || +- (tty->flags & (1 << TTY_IO_ERROR))) { +- port->flags |= ASYNC_NORMAL_ACTIVE; +- return 0; +- } +- +- if (tty->termios->c_cflag & CLOCAL) +- do_clocal = 1; +- +- /* +- * Block waiting for the carrier detect and the line to become +- * free (i.e., not in use by the callout). While we are in +- * this loop, port->count is dropped by one, so that +- * rs_close() knows when to free things. We restore it upon +- * exit, either normal or abnormal. +- */ +- retval = 0; +- add_wait_queue(&port->open_wait, &wait); +-#ifdef SERIAL_DEBUG_OPEN +- printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n", +- info->line, port->count); +-#endif +- spin_lock_irqsave(&info->lock, flags); +- if (!tty_hung_up_p(filp)) +- port->count--; +- port->blocked_open++; +- while (1) { +- if ((tty->termios->c_cflag & CBAUD)) { +- unsigned int scratch; +- +- serial_out(info, UART_ESI_CMD1, ESI_READ_UART); +- serial_out(info, UART_ESI_CMD2, UART_MCR); +- scratch = serial_in(info, UART_ESI_STAT1); +- serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); +- serial_out(info, UART_ESI_CMD2, UART_MCR); +- serial_out(info, UART_ESI_CMD2, +- scratch | UART_MCR_DTR | UART_MCR_RTS); +- } +- set_current_state(TASK_INTERRUPTIBLE); +- if (tty_hung_up_p(filp) || +- !(port->flags & ASYNC_INITIALIZED)) { +-#ifdef SERIAL_DO_RESTART +- if (port->flags & ASYNC_HUP_NOTIFY) +- retval = -EAGAIN; +- else +- retval = -ERESTARTSYS; +-#else +- retval = -EAGAIN; +-#endif +- break; +- } +- +- cd = tty_port_carrier_raised(port); +- +- if (!(port->flags & ASYNC_CLOSING) && +- (do_clocal)) +- break; +- if (signal_pending(current)) { +- retval = -ERESTARTSYS; +- break; +- } +-#ifdef SERIAL_DEBUG_OPEN +- printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n", +- info->line, port->count); +-#endif +- spin_unlock_irqrestore(&info->lock, flags); +- schedule(); +- spin_lock_irqsave(&info->lock, flags); +- } +- set_current_state(TASK_RUNNING); +- remove_wait_queue(&port->open_wait, &wait); +- if (!tty_hung_up_p(filp)) +- port->count++; +- port->blocked_open--; +- spin_unlock_irqrestore(&info->lock, flags); +-#ifdef SERIAL_DEBUG_OPEN +- printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n", +- info->line, port->count); +-#endif +- if (retval) +- return retval; +- port->flags |= ASYNC_NORMAL_ACTIVE; +- return 0; +-} +- +-/* +- * This routine is called whenever a serial port is opened. It +- * enables interrupts for a serial port, linking in its async structure into +- * the IRQ chain. It also performs the serial-specific +- * initialization for the tty structure. +- */ +-static int esp_open(struct tty_struct *tty, struct file *filp) +-{ +- struct esp_struct *info; +- int retval, line; +- unsigned long flags; +- +- line = tty->index; +- if ((line < 0) || (line >= NR_PORTS)) +- return -ENODEV; +- +- /* find the port in the chain */ +- +- info = ports; +- +- while (info && (info->line != line)) +- info = info->next_port; +- +- if (!info) { +- serial_paranoia_check(info, tty->name, "esp_open"); +- return -ENODEV; +- } +- +-#ifdef SERIAL_DEBUG_OPEN +- printk(KERN_DEBUG "esp_open %s, count = %d\n", tty->name, info->port.count); +-#endif +- spin_lock_irqsave(&info->lock, flags); +- info->port.count++; +- tty->driver_data = info; +- info->port.tty = tty; +- +- spin_unlock_irqrestore(&info->lock, flags); +- +- /* +- * Start up serial port +- */ +- retval = startup(info); +- if (retval) +- return retval; +- +- retval = block_til_ready(tty, filp, info); +- if (retval) { +-#ifdef SERIAL_DEBUG_OPEN +- printk(KERN_DEBUG "esp_open returning after block_til_ready with %d\n", +- retval); +-#endif +- return retval; +- } +-#ifdef SERIAL_DEBUG_OPEN +- printk(KERN_DEBUG "esp_open %s successful...", tty->name); +-#endif +- return 0; +-} +- +-/* +- * --------------------------------------------------------------------- +- * espserial_init() and friends +- * +- * espserial_init() is called at boot-time to initialize the serial driver. +- * --------------------------------------------------------------------- +- */ +- +-/* +- * This routine prints out the appropriate serial driver version +- * number, and identifies which options were configured into this +- * driver. +- */ +- +-static void __init show_serial_version(void) +-{ +- printk(KERN_INFO "%s version %s (DMA %u)\n", +- serial_name, serial_version, dma); +-} +- +-/* +- * This routine is called by espserial_init() to initialize a specific serial +- * port. +- */ +-static int autoconfig(struct esp_struct *info) +-{ +- int port_detected = 0; +- unsigned long flags; +- +- if (!request_region(info->io_port, REGION_SIZE, "esp serial")) +- return -EIO; +- +- spin_lock_irqsave(&info->lock, flags); +- /* +- * Check for ESP card +- */ +- +- if (serial_in(info, UART_ESI_BASE) == 0xf3) { +- serial_out(info, UART_ESI_CMD1, 0x00); +- serial_out(info, UART_ESI_CMD1, 0x01); +- +- if ((serial_in(info, UART_ESI_STAT2) & 0x70) == 0x20) { +- port_detected = 1; +- +- if (!(info->irq)) { +- serial_out(info, UART_ESI_CMD1, 0x02); +- +- if (serial_in(info, UART_ESI_STAT1) & 0x01) +- info->irq = 3; +- else +- info->irq = 4; +- } +- +- +- /* put card in enhanced mode */ +- /* this prevents access through */ +- /* the "old" IO ports */ +- esp_basic_init(info); +- +- /* clear out MCR */ +- serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); +- serial_out(info, UART_ESI_CMD2, UART_MCR); +- serial_out(info, UART_ESI_CMD2, 0x00); +- } +- } +- if (!port_detected) +- release_region(info->io_port, REGION_SIZE); +- +- spin_unlock_irqrestore(&info->lock, flags); +- return (port_detected); +-} +- +-static const struct tty_operations esp_ops = { +- .open = esp_open, +- .close = rs_close, +- .write = rs_write, +- .put_char = rs_put_char, +- .flush_chars = rs_flush_chars, +- .write_room = rs_write_room, +- .chars_in_buffer = rs_chars_in_buffer, +- .flush_buffer = rs_flush_buffer, +- .ioctl = rs_ioctl, +- .throttle = rs_throttle, +- .unthrottle = rs_unthrottle, +- .set_termios = rs_set_termios, +- .stop = rs_stop, +- .start = rs_start, +- .hangup = esp_hangup, +- .break_ctl = esp_break, +- .wait_until_sent = rs_wait_until_sent, +- .tiocmget = esp_tiocmget, +- .tiocmset = esp_tiocmset, +-}; +- +-static const struct tty_port_operations esp_port_ops = { +- .esp_carrier_raised, +-}; +- +-/* +- * The serial driver boot-time initialization code! +- */ +-static int __init espserial_init(void) +-{ +- int i, offset; +- struct esp_struct *info; +- struct esp_struct *last_primary = NULL; +- int esp[] = { 0x100, 0x140, 0x180, 0x200, 0x240, 0x280, 0x300, 0x380 }; +- +- esp_driver = alloc_tty_driver(NR_PORTS); +- if (!esp_driver) +- return -ENOMEM; +- +- for (i = 0; i < NR_PRIMARY; i++) { +- if (irq[i] != 0) { +- if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) || +- (irq[i] == 8) || (irq[i] == 13)) +- irq[i] = 0; +- else if (irq[i] == 2) +- irq[i] = 9; +- } +- } +- +- if ((dma != 1) && (dma != 3)) +- dma = 0; +- +- if ((rx_trigger < 1) || (rx_trigger > 1023)) +- rx_trigger = 768; +- +- if ((tx_trigger < 1) || (tx_trigger > 1023)) +- tx_trigger = 768; +- +- if ((flow_off < 1) || (flow_off > 1023)) +- flow_off = 1016; +- +- if ((flow_on < 1) || (flow_on > 1023)) +- flow_on = 944; +- +- if ((rx_timeout < 0) || (rx_timeout > 255)) +- rx_timeout = 128; +- +- if (flow_on >= flow_off) +- flow_on = flow_off - 1; +- +- show_serial_version(); +- +- /* Initialize the tty_driver structure */ +- +- esp_driver->owner = THIS_MODULE; +- esp_driver->name = "ttyP"; +- esp_driver->major = ESP_IN_MAJOR; +- esp_driver->minor_start = 0; +- esp_driver->type = TTY_DRIVER_TYPE_SERIAL; +- esp_driver->subtype = SERIAL_TYPE_NORMAL; +- esp_driver->init_termios = tty_std_termios; +- esp_driver->init_termios.c_cflag = +- B9600 | CS8 | CREAD | HUPCL | CLOCAL; +- esp_driver->init_termios.c_ispeed = 9600; +- esp_driver->init_termios.c_ospeed = 9600; +- esp_driver->flags = TTY_DRIVER_REAL_RAW; +- tty_set_operations(esp_driver, &esp_ops); +- if (tty_register_driver(esp_driver)) { +- printk(KERN_ERR "Couldn't register esp serial driver"); +- put_tty_driver(esp_driver); +- return 1; +- } +- +- info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL); +- +- if (!info) { +- printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); +- tty_unregister_driver(esp_driver); +- put_tty_driver(esp_driver); +- return 1; +- } +- +- spin_lock_init(&info->lock); +- /* rx_trigger, tx_trigger are needed by autoconfig */ +- info->config.rx_trigger = rx_trigger; +- info->config.tx_trigger = tx_trigger; +- +- i = 0; +- offset = 0; +- +- do { +- tty_port_init(&info->port); +- info->port.ops = &esp_port_ops; +- info->io_port = esp[i] + offset; +- info->irq = irq[i]; +- info->line = (i * 8) + (offset / 8); +- +- if (!autoconfig(info)) { +- i++; +- offset = 0; +- continue; +- } +- +- info->custom_divisor = (divisor[i] >> (offset / 2)) & 0xf; +- info->port.flags = STD_COM_FLAGS; +- if (info->custom_divisor) +- info->port.flags |= ASYNC_SPD_CUST; +- info->magic = ESP_MAGIC; +- info->close_delay = 5*HZ/10; +- info->closing_wait = 30*HZ; +- info->config.rx_timeout = rx_timeout; +- info->config.flow_on = flow_on; +- info->config.flow_off = flow_off; +- info->config.pio_threshold = pio_threshold; +- info->next_port = ports; +- init_waitqueue_head(&info->break_wait); +- ports = info; +- printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ", +- info->line, info->io_port, info->irq); +- +- if (info->line % 8) { +- printk("secondary port\n"); +- /* 8 port cards can't do DMA */ +- info->stat_flags |= ESP_STAT_NEVER_DMA; +- +- if (last_primary) +- last_primary->stat_flags |= ESP_STAT_NEVER_DMA; +- } else { +- printk("primary port\n"); +- last_primary = info; +- irq[i] = info->irq; +- } +- +- if (!dma) +- info->stat_flags |= ESP_STAT_NEVER_DMA; +- +- info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL); +- if (!info) { +- printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); +- /* allow use of the already detected ports */ +- return 0; +- } +- +- spin_lock_init(&info->lock); +- /* rx_trigger, tx_trigger are needed by autoconfig */ +- info->config.rx_trigger = rx_trigger; +- info->config.tx_trigger = tx_trigger; +- +- if (offset == 56) { +- i++; +- offset = 0; +- } else { +- offset += 8; +- } +- } while (i < NR_PRIMARY); +- +- /* free the last port memory allocation */ +- kfree(info); +- +- return 0; +-} +- +-static void __exit espserial_exit(void) +-{ +- int e1; +- struct esp_struct *temp_async; +- struct esp_pio_buffer *pio_buf; +- +- e1 = tty_unregister_driver(esp_driver); +- if (e1) +- printk(KERN_ERR "esp: failed to unregister driver (%d)\n", e1); +- put_tty_driver(esp_driver); +- +- while (ports) { +- if (ports->io_port) +- release_region(ports->io_port, REGION_SIZE); +- temp_async = ports->next_port; +- kfree(ports); +- ports = temp_async; +- } +- +- if (dma_buffer) +- free_pages((unsigned long)dma_buffer, +- get_order(DMA_BUFFER_SZ)); +- +- while (free_pio_buf) { +- pio_buf = free_pio_buf->next; +- kfree(free_pio_buf); +- free_pio_buf = pio_buf; +- } +-} +- +-module_init(espserial_init); +-module_exit(espserial_exit); +--- a/drivers/char/Kconfig ++++ b/drivers/char/Kconfig +@@ -201,19 +201,6 @@ config DIGIEPCA + To compile this driver as a module, choose M here: the + module will be called epca. + +-config ESPSERIAL +- tristate "Hayes ESP serial port support" +- depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API && BROKEN +- help +- This is a driver which supports Hayes ESP serial ports. Both single +- port cards and multiport cards are supported. Make sure to read +- <file:Documentation/hayes-esp.txt>. +- +- To compile this driver as a module, choose M here: the +- module will be called esp. +- +- If unsure, say N. +- + config MOXA_INTELLIO + tristate "Moxa Intellio support" + depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -18,7 +18,6 @@ obj-$(CONFIG_CONSOLE_TRANSLATIONS) += co + obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o + obj-$(CONFIG_AUDIT) += tty_audit.o + obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o +-obj-$(CONFIG_ESPSERIAL) += esp.o + obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o + obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o + obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o +--- a/include/linux/hayesesp.h ++++ /dev/null +@@ -1,114 +0,0 @@ +-#ifndef HAYESESP_H +-#define HAYESESP_H +- +-struct hayes_esp_config { +- short flow_on; +- short flow_off; +- short rx_trigger; +- short tx_trigger; +- short pio_threshold; +- unsigned char rx_timeout; +- char dma_channel; +-}; +- +-#ifdef __KERNEL__ +- +-#define ESP_DMA_CHANNEL 0 +-#define ESP_RX_TRIGGER 768 +-#define ESP_TX_TRIGGER 768 +-#define ESP_FLOW_OFF 1016 +-#define ESP_FLOW_ON 944 +-#define ESP_RX_TMOUT 128 +-#define ESP_PIO_THRESHOLD 32 +- +-#define ESP_IN_MAJOR 57 /* major dev # for dial in */ +-#define ESP_OUT_MAJOR 58 /* major dev # for dial out */ +-#define ESPC_SCALE 3 +-#define UART_ESI_BASE 0x00 +-#define UART_ESI_SID 0x01 +-#define UART_ESI_RX 0x02 +-#define UART_ESI_TX 0x02 +-#define UART_ESI_CMD1 0x04 +-#define UART_ESI_CMD2 0x05 +-#define UART_ESI_STAT1 0x04 +-#define UART_ESI_STAT2 0x05 +-#define UART_ESI_RWS 0x07 +- +-#define UART_IER_DMA_TMOUT 0x80 +-#define UART_IER_DMA_TC 0x08 +- +-#define ESI_SET_IRQ 0x04 +-#define ESI_SET_DMA_TMOUT 0x05 +-#define ESI_SET_SRV_MASK 0x06 +-#define ESI_SET_ERR_MASK 0x07 +-#define ESI_SET_FLOW_CNTL 0x08 +-#define ESI_SET_FLOW_CHARS 0x09 +-#define ESI_SET_FLOW_LVL 0x0a +-#define ESI_SET_TRIGGER 0x0b +-#define ESI_SET_RX_TIMEOUT 0x0c +-#define ESI_SET_FLOW_TMOUT 0x0d +-#define ESI_WRITE_UART 0x0e +-#define ESI_READ_UART 0x0f +-#define ESI_SET_MODE 0x10 +-#define ESI_GET_ERR_STAT 0x12 +-#define ESI_GET_UART_STAT 0x13 +-#define ESI_GET_RX_AVAIL 0x14 +-#define ESI_GET_TX_AVAIL 0x15 +-#define ESI_START_DMA_RX 0x16 +-#define ESI_START_DMA_TX 0x17 +-#define ESI_ISSUE_BREAK 0x1a +-#define ESI_FLUSH_RX 0x1b +-#define ESI_FLUSH_TX 0x1c +-#define ESI_SET_BAUD 0x1d +-#define ESI_SET_ENH_IRQ 0x1f +-#define ESI_SET_REINTR 0x20 +-#define ESI_SET_PRESCALAR 0x23 +-#define ESI_NO_COMMAND 0xff +- +-#define ESP_STAT_RX_TIMEOUT 0x01 +-#define ESP_STAT_DMA_RX 0x02 +-#define ESP_STAT_DMA_TX 0x04 +-#define ESP_STAT_NEVER_DMA 0x08 +-#define ESP_STAT_USE_PIO 0x10 +- +-#define ESP_MAGIC 0x53ee +-#define ESP_XMIT_SIZE 4096 +- +-struct esp_struct { +- int magic; +- struct tty_port port; +- spinlock_t lock; +- int io_port; +- int irq; +- int read_status_mask; +- int ignore_status_mask; +- int timeout; +- int stat_flags; +- int custom_divisor; +- int close_delay; +- unsigned short closing_wait; +- unsigned short closing_wait2; +- int IER; /* Interrupt Enable Register */ +- int MCR; /* Modem control register */ +- unsigned long last_active; +- int line; +- unsigned char *xmit_buf; +- int xmit_head; +- int xmit_tail; +- int xmit_cnt; +- wait_queue_head_t break_wait; +- struct async_icount icount; /* kernel counters for the 4 input interrupts */ +- struct hayes_esp_config config; /* port configuration */ +- struct esp_struct *next_port; /* For the linked list */ +-}; +- +-struct esp_pio_buffer { +- unsigned char data[1024]; +- struct esp_pio_buffer *next; +-}; +- +-#endif /* __KERNEL__ */ +- +- +-#endif /* ESP_H */ +- diff --git a/usb.current/usb-ehci-fix-ist-boundary-checking-interval-math.patch b/usb.current/usb-ehci-fix-ist-boundary-checking-interval-math.patch new file mode 100644 index 00000000000000..76b82cef1fb1ee --- /dev/null +++ b/usb.current/usb-ehci-fix-ist-boundary-checking-interval-math.patch @@ -0,0 +1,62 @@ +From sarah.a.sharp@linux.intel.com Mon Oct 12 15:13:10 2009 +From: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Date: Fri, 9 Oct 2009 12:28:41 -0700 +Subject: USB: ehci: Fix IST boundary checking interval math. +To: Greg KH <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, Alan Stern <stern@rowland.harvard.edu>, David Brownell <david-b@pacbell.net> +Message-ID: <20091009192841.GA5279@gamba.jf.intel.com> +Content-Disposition: inline + + +When the EHCI driver falls behind in its scheduling, the active stream's +first empty microframe may be in the past with respect to the current +microframe. The code attempts to move the starting microframe ("start") N +number of microframes forward, where N is the interval of endpoint. +However, stream->interval is a copy of the endpoint's bInterval, which is +designated in frames for FS devices, and microframes for HS devices. +Convert stream->interval to microframes before using it to move the +starting microframe forward. + +Acked-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/ehci-sched.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/usb/host/ehci-sched.c ++++ b/drivers/usb/host/ehci-sched.c +@@ -1400,6 +1400,10 @@ iso_stream_schedule ( + goto fail; + } + ++ period = urb->interval; ++ if (!stream->highspeed) ++ period <<= 3; ++ + now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; + + /* when's the last uframe this urb could start? */ +@@ -1417,8 +1421,8 @@ iso_stream_schedule ( + + /* Fell behind (by up to twice the slop amount)? */ + if (start >= max - 2 * 8 * SCHEDULE_SLOP) +- start += stream->interval * DIV_ROUND_UP( +- max - start, stream->interval) - mod; ++ start += period * DIV_ROUND_UP( ++ max - start, period) - mod; + + /* Tried to schedule too far into the future? */ + if (unlikely((start + sched->span) >= max)) { +@@ -1441,10 +1445,6 @@ iso_stream_schedule ( + + /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ + +- period = urb->interval; +- if (!stream->highspeed) +- period <<= 3; +- + /* find a uframe slot with enough bandwidth */ + for (; start < (stream->next_uframe + period); start++) { + int enough_space; diff --git a/usb.current/usb-musb-invert-arch-depend-string.patch b/usb.current/usb-musb-invert-arch-depend-string.patch new file mode 100644 index 00000000000000..c2c5ec13e8fd73 --- /dev/null +++ b/usb.current/usb-musb-invert-arch-depend-string.patch @@ -0,0 +1,34 @@ +From vapier@gentoo.org Mon Oct 12 15:01:06 2009 +From: Mike Frysinger <vapier@gentoo.org> +Date: Mon, 12 Oct 2009 09:49:56 -0400 +Subject: USB: musb: invert arch depend string +To: Ingo Molnar <mingo@redhat.com>, Linus Torvalds <torvalds@linux-foundation.org>, Greg Kroah-Hartman <gregkh@suse.de> +Cc: Felipe Balbi <felipe.balbi@nokia.com> +Message-ID: <1255355396-20533-1-git-send-email-vapier@gentoo.org> + + +The MUSB code relies on platform implementations that currently only +exists for Arm and Blackfin processors, so have the MUSB Kconfig depend +upon those arches. + +This should prevent other arches from building MUSB via randconfig. + +Reported-by: Ingo Molnar <mingo@elte.hu> +Signed-off-by: Mike Frysinger <vapier@gentoo.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/musb/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/musb/Kconfig ++++ b/drivers/usb/musb/Kconfig +@@ -9,7 +9,7 @@ comment "Enable Host or Gadget support t + # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller + config USB_MUSB_HDRC + depends on (USB || USB_GADGET) +- depends on !SUPERH ++ depends on (ARM || BLACKFIN) + select NOP_USB_XCEIV if ARCH_DAVINCI + select TWL4030_USB if MACH_OMAP_3430SDP + select NOP_USB_XCEIV if MACH_OMAP3EVM diff --git a/usb.current/usb-option-support-for-airplus-mcd650-datacard.patch b/usb.current/usb-option-support-for-airplus-mcd650-datacard.patch new file mode 100644 index 00000000000000..6648d6bee3449a --- /dev/null +++ b/usb.current/usb-option-support-for-airplus-mcd650-datacard.patch @@ -0,0 +1,41 @@ +From sidhpurwala.huzaifa@gmail.com Mon Oct 12 15:08:28 2009 +From: Huzaifa Sidhpurwala <sidhpurwala.huzaifa@gmail.com> +Date: Mon, 12 Oct 2009 14:34:45 +0530 +Subject: USB: option: Support for AIRPLUS MCD650 Datacard +To: greg@kroah.org +Cc: linux-usb@vger.kernel.org +Message-ID: <4AD2F12D.1010800@gmail.com> + + +Here is a patch for Airplus MCD 650 card + +Note: This device is with Victor V Kudlak, and he confirmed that this +device works with the patch. + +Signed-off-by: Huzaifa Sidhpurwala <sidhpurwala.huzaifa@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/option.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -328,6 +328,9 @@ static int option_resume(struct usb_ser + #define ALCATEL_VENDOR_ID 0x1bbb + #define ALCATEL_PRODUCT_X060S 0x0000 + ++/* Airplus products */ ++#define AIRPLUS_VENDOR_ID 0x1011 ++#define AIRPLUS_PRODUCT_MCD650 0x3198 + + static struct usb_device_id option_ids[] = { + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, +@@ -589,6 +592,7 @@ static struct usb_device_id option_ids[] + { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, + { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) }, ++ { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, + { } /* Terminating entry */ + }; + MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/usb.current/usb-rename-documentation-abi-...-sysfs-class-usb_host.patch b/usb.current/usb-rename-documentation-abi-...-sysfs-class-usb_host.patch new file mode 100644 index 00000000000000..9c6c765950a30b --- /dev/null +++ b/usb.current/usb-rename-documentation-abi-...-sysfs-class-usb_host.patch @@ -0,0 +1,76 @@ +From david.vrabel@csr.com Mon Oct 12 15:06:53 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Mon, 12 Oct 2009 15:45:13 +0000 +Subject: USB: rename Documentation/ABI/.../sysfs-class-usb_host +To: Greg KH <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, David Vrabel <david.vrabel@csr.com> +Message-ID: <1255362318-10226-2-git-send-email-david.vrabel@csr.com> + + +The usb_host class is no more. Rename its documentation file (which +only contained WUSB specific files) to .../sysfs-class-uwb_rc-wusbhc. + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + Documentation/ABI/testing/sysfs-class-usb_host | 25 -------------------- + Documentation/ABI/testing/sysfs-class-uwb_rc-wusbhc | 25 ++++++++++++++++++++ + 2 files changed, 25 insertions(+), 25 deletions(-) + +--- a/Documentation/ABI/testing/sysfs-class-usb_host ++++ /dev/null +@@ -1,25 +0,0 @@ +-What: /sys/class/usb_host/usb_hostN/wusb_chid +-Date: July 2008 +-KernelVersion: 2.6.27 +-Contact: David Vrabel <david.vrabel@csr.com> +-Description: +- Write the CHID (16 space-separated hex octets) for this host controller. +- This starts the host controller, allowing it to accept connection from +- WUSB devices. +- +- Set an all zero CHID to stop the host controller. +- +-What: /sys/class/usb_host/usb_hostN/wusb_trust_timeout +-Date: July 2008 +-KernelVersion: 2.6.27 +-Contact: David Vrabel <david.vrabel@csr.com> +-Description: +- Devices that haven't sent a WUSB packet to the host +- within 'wusb_trust_timeout' ms are considered to have +- disconnected and are removed. The default value of +- 4000 ms is the value required by the WUSB +- specification. +- +- Since this relates to security (specifically, the +- lifetime of PTKs and GTKs) it should not be changed +- from the default. +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-class-uwb_rc-wusbhc +@@ -0,0 +1,25 @@ ++What: /sys/class/uwb_rc/uwbN/wusbhc/wusb_chid ++Date: July 2008 ++KernelVersion: 2.6.27 ++Contact: David Vrabel <david.vrabel@csr.com> ++Description: ++ Write the CHID (16 space-separated hex octets) for this host controller. ++ This starts the host controller, allowing it to accept connection from ++ WUSB devices. ++ ++ Set an all zero CHID to stop the host controller. ++ ++What: /sys/class/uwb_rc/uwbN/wusbhc/wusb_trust_timeout ++Date: July 2008 ++KernelVersion: 2.6.27 ++Contact: David Vrabel <david.vrabel@csr.com> ++Description: ++ Devices that haven't sent a WUSB packet to the host ++ within 'wusb_trust_timeout' ms are considered to have ++ disconnected and are removed. The default value of ++ 4000 ms is the value required by the WUSB ++ specification. ++ ++ Since this relates to security (specifically, the ++ lifetime of PTKs and GTKs) it should not be changed ++ from the default. diff --git a/usb.current/usb-whci-hcd-always-do-an-update-after-processing-a-halted-qtd.patch b/usb.current/usb-whci-hcd-always-do-an-update-after-processing-a-halted-qtd.patch new file mode 100644 index 00000000000000..6dcc31e7de095c --- /dev/null +++ b/usb.current/usb-whci-hcd-always-do-an-update-after-processing-a-halted-qtd.patch @@ -0,0 +1,46 @@ +From david.vrabel@csr.com Mon Oct 12 15:07:50 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Mon, 12 Oct 2009 15:45:16 +0000 +Subject: USB: whci-hcd: always do an update after processing a halted qTD +To: Greg KH <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, David Vrabel <david.vrabel@csr.com> +Message-ID: <1255362318-10226-5-git-send-email-david.vrabel@csr.com> + + +A halted qTD always triggers a hardware list update because the qset was +either removed or reactivated. + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/whci/asl.c | 4 ++++ + drivers/usb/host/whci/pzl.c | 4 ++++ + 2 files changed, 8 insertions(+) + +--- a/drivers/usb/host/whci/asl.c ++++ b/drivers/usb/host/whci/asl.c +@@ -115,6 +115,10 @@ static uint32_t process_qset(struct whc + if (status & QTD_STS_HALTED) { + /* Ug, an error. */ + process_halted_qtd(whc, qset, td); ++ /* A halted qTD always triggers an update ++ because the qset was either removed or ++ reactivated. */ ++ update |= WHC_UPDATE_UPDATED; + goto done; + } + +--- a/drivers/usb/host/whci/pzl.c ++++ b/drivers/usb/host/whci/pzl.c +@@ -121,6 +121,10 @@ static enum whc_update pzl_process_qset( + if (status & QTD_STS_HALTED) { + /* Ug, an error. */ + process_halted_qtd(whc, qset, td); ++ /* A halted qTD always triggers an update ++ because the qset was either removed or ++ reactivated. */ ++ update |= WHC_UPDATE_UPDATED; + goto done; + } + diff --git a/usb.current/usb-whci-hcd-handle-early-deletion-of-endpoints.patch b/usb.current/usb-whci-hcd-handle-early-deletion-of-endpoints.patch new file mode 100644 index 00000000000000..fe592724a4e813 --- /dev/null +++ b/usb.current/usb-whci-hcd-handle-early-deletion-of-endpoints.patch @@ -0,0 +1,104 @@ +From david.vrabel@csr.com Mon Oct 12 15:07:32 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Mon, 12 Oct 2009 15:45:15 +0000 +Subject: USB: whci-hcd: handle early deletion of endpoints +To: Greg KH <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, David Vrabel <david.vrabel@csr.com> +Message-ID: <1255362318-10226-4-git-send-email-david.vrabel@csr.com> + + +If an endpoint is deleted before it's been fully added to the hardware +list, the associated qset will not be fully initialized and an oops will +occur when complete(&qset->remove_complete) is called. This can happen +if a queued URB is cancelled. + +Fix this by only removing the qset from the hardware list if the +cancelled URB had qTDs. + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/whci/asl.c | 19 ++++++++++++------- + drivers/usb/host/whci/pzl.c | 20 +++++++++++++------- + 2 files changed, 25 insertions(+), 14 deletions(-) + +--- a/drivers/usb/host/whci/asl.c ++++ b/drivers/usb/host/whci/asl.c +@@ -305,6 +305,7 @@ int asl_urb_dequeue(struct whc *whc, str + struct whc_urb *wurb = urb->hcpriv; + struct whc_qset *qset = wurb->qset; + struct whc_std *std, *t; ++ bool has_qtd = false; + int ret; + unsigned long flags; + +@@ -315,17 +316,21 @@ int asl_urb_dequeue(struct whc *whc, str + goto out; + + list_for_each_entry_safe(std, t, &qset->stds, list_node) { +- if (std->urb == urb) ++ if (std->urb == urb) { ++ if (std->qtd) ++ has_qtd = true; + qset_free_std(whc, std); +- else ++ } else + std->qtd = NULL; /* so this std is re-added when the qset is */ + } + +- asl_qset_remove(whc, qset); +- wurb->status = status; +- wurb->is_async = true; +- queue_work(whc->workqueue, &wurb->dequeue_work); +- ++ if (has_qtd) { ++ asl_qset_remove(whc, qset); ++ wurb->status = status; ++ wurb->is_async = true; ++ queue_work(whc->workqueue, &wurb->dequeue_work); ++ } else ++ qset_remove_urb(whc, qset, urb, status); + out: + spin_unlock_irqrestore(&whc->lock, flags); + +--- a/drivers/usb/host/whci/pzl.c ++++ b/drivers/usb/host/whci/pzl.c +@@ -333,6 +333,7 @@ int pzl_urb_dequeue(struct whc *whc, str + struct whc_urb *wurb = urb->hcpriv; + struct whc_qset *qset = wurb->qset; + struct whc_std *std, *t; ++ bool has_qtd = false; + int ret; + unsigned long flags; + +@@ -343,17 +344,22 @@ int pzl_urb_dequeue(struct whc *whc, str + goto out; + + list_for_each_entry_safe(std, t, &qset->stds, list_node) { +- if (std->urb == urb) ++ if (std->urb == urb) { ++ if (std->qtd) ++ has_qtd = true; + qset_free_std(whc, std); +- else ++ } else + std->qtd = NULL; /* so this std is re-added when the qset is */ + } + +- pzl_qset_remove(whc, qset); +- wurb->status = status; +- wurb->is_async = false; +- queue_work(whc->workqueue, &wurb->dequeue_work); +- ++ if (has_qtd) { ++ pzl_qset_remove(whc, qset); ++ update_pzl_hw_view(whc); ++ wurb->status = status; ++ wurb->is_async = false; ++ queue_work(whc->workqueue, &wurb->dequeue_work); ++ } else ++ qset_remove_urb(whc, qset, urb, status); + out: + spin_unlock_irqrestore(&whc->lock, flags); + diff --git a/usb.current/usb-wusb-don-t-use-the-stack-to-read-security-descriptor.patch b/usb.current/usb-wusb-don-t-use-the-stack-to-read-security-descriptor.patch new file mode 100644 index 00000000000000..16b4b5446ac69e --- /dev/null +++ b/usb.current/usb-wusb-don-t-use-the-stack-to-read-security-descriptor.patch @@ -0,0 +1,103 @@ +From david.vrabel@csr.com Mon Oct 12 15:07:12 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Mon, 12 Oct 2009 15:45:14 +0000 +Subject: USB: wusb: don't use the stack to read security descriptor +To: Greg KH <gregkh@suse.de> +Cc: linux-usb@vger.kernel.org, David Vrabel <david.vrabel@csr.com> +Message-ID: <1255362318-10226-3-git-send-email-david.vrabel@csr.com> + + +From: Stefano Panella <stefano.panella@csr.com> + +An urb's transfer buffer must be kmalloc'd memory and not point to the +stack or a DMA API warning results. + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/wusbcore/security.c | 41 ++++++++++++++++++---------------------- + 1 file changed, 19 insertions(+), 22 deletions(-) + +--- a/drivers/usb/wusbcore/security.c ++++ b/drivers/usb/wusbcore/security.c +@@ -200,35 +200,40 @@ int wusb_dev_sec_add(struct wusbhc *wusb + { + int result, bytes, secd_size; + struct device *dev = &usb_dev->dev; +- struct usb_security_descriptor secd; ++ struct usb_security_descriptor *secd; + const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL; +- void *secd_buf; + const void *itr, *top; + char buf[64]; + ++ secd = kmalloc(sizeof(struct usb_security_descriptor), GFP_KERNEL); ++ if (secd == NULL) { ++ result = -ENOMEM; ++ goto out; ++ } ++ + result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, +- 0, &secd, sizeof(secd)); ++ 0, secd, sizeof(struct usb_security_descriptor)); + if (result < sizeof(secd)) { + dev_err(dev, "Can't read security descriptor or " + "not enough data: %d\n", result); +- goto error_secd; ++ goto out; + } +- secd_size = le16_to_cpu(secd.wTotalLength); +- secd_buf = kmalloc(secd_size, GFP_KERNEL); +- if (secd_buf == NULL) { ++ secd_size = le16_to_cpu(secd->wTotalLength); ++ secd = krealloc(secd, secd_size, GFP_KERNEL); ++ if (secd == NULL) { + dev_err(dev, "Can't allocate space for security descriptors\n"); +- goto error_secd_alloc; ++ goto out; + } + result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, +- 0, secd_buf, secd_size); ++ 0, secd, secd_size); + if (result < secd_size) { + dev_err(dev, "Can't read security descriptor or " + "not enough data: %d\n", result); +- goto error_secd_all; ++ goto out; + } + bytes = 0; +- itr = secd_buf + sizeof(secd); +- top = secd_buf + result; ++ itr = &secd[1]; ++ top = (void *)secd + result; + while (itr < top) { + etd = itr; + if (top - itr < sizeof(*etd)) { +@@ -259,24 +264,16 @@ int wusb_dev_sec_add(struct wusbhc *wusb + dev_err(dev, "WUSB device doesn't support CCM1 encryption, " + "can't use!\n"); + result = -EINVAL; +- goto error_no_ccm1; ++ goto out; + } + wusb_dev->ccm1_etd = *ccm1_etd; + dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n", + buf, wusb_et_name(ccm1_etd->bEncryptionType), + ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex); + result = 0; +- kfree(secd_buf); + out: ++ kfree(secd); + return result; +- +- +-error_no_ccm1: +-error_secd_all: +- kfree(secd_buf); +-error_secd_alloc: +-error_secd: +- goto out; + } + + void wusb_dev_sec_rm(struct wusb_dev *wusb_dev) |
