Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Thu, 19 Oct 2006 00:49:19 +0000 (17:49 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 19 Oct 2006 00:49:19 +0000 (17:49 -0700)
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6:
  [IA64] Count resched interrupts
  [IA64] remove unused acpi_kbd_controller_present, acpi_legacy_devices
  [IA64] update sn2_defconfig
  [IA64] reformat pal.S to fit in 80 columns, fix typos
  [IA64] remove unused PAL_CALL_IC_OFF
  [IA64] - Allow IPIs in timer loop
  [IA64] move ioremap/ioremap_nocache under __KERNEL__
  [IA64] perfmon fix for global IRQ fix

92 files changed:
Documentation/input/xpad.txt
arch/arm/mach-footbridge/dc21285.c
arch/arm/mach-ixp2000/ixdp2400.c
arch/arm/mach-ixp2000/ixdp2800.c
arch/arm/mach-ixp2000/ixdp2x00.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-sa1100/cpu-sa1110.c
arch/arm/oprofile/op_model_xscale.c
arch/arm/tools/mach-types
arch/sparc/Kconfig
arch/sparc/Makefile
arch/sparc/kernel/irq.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/time.c
arch/sparc/oprofile/Kconfig [new file with mode: 0644]
arch/sparc/oprofile/Makefile [new file with mode: 0644]
arch/sparc/oprofile/init.c [new file with mode: 0644]
arch/sparc64/defconfig
arch/sparc64/kernel/pci_common.c
arch/sparc64/kernel/pci_sabre.c
arch/sparc64/kernel/setup.c
drivers/infiniband/hw/amso1100/c2.c
drivers/infiniband/hw/amso1100/c2_rnic.c
drivers/infiniband/hw/ipath/ipath_diag.c
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/ipath/ipath_kernel.h
drivers/infiniband/hw/mthca/mthca_cq.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/hw/mthca/mthca_srq.c
drivers/input/keyboard/corgikbd.c
drivers/input/keyboard/locomokbd.c
drivers/input/keyboard/spitzkbd.c
drivers/input/touchscreen/corgi_ts.c
drivers/net/myri_code.h
drivers/net/myri_sbus.c
drivers/net/sunbmac.c
drivers/sbus/char/bbc_envctrl.c
drivers/sbus/char/envctrl.c
drivers/scsi/qlogicpti.c
drivers/scsi/qlogicpti_asm.c
drivers/usb/Makefile
drivers/usb/atm/cxacru.c
drivers/usb/atm/speedtch.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/atm/usbatm.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/usblp.c
drivers/usb/core/devio.c
drivers/usb/core/endpoint.c
drivers/usb/gadget/net2280.c
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci.h
drivers/usb/host/ohci-pnx4008.c
drivers/usb/host/uhci-hcd.c
drivers/usb/input/Kconfig
drivers/usb/input/Makefile
drivers/usb/input/hid-core.c
drivers/usb/input/trancevibrator.c [deleted file]
drivers/usb/input/usbtouchscreen.c
drivers/usb/input/wacom.h
drivers/usb/input/wacom_sys.c
drivers/usb/input/wacom_wac.c
drivers/usb/input/wacom_wac.h
drivers/usb/input/xpad.c
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
drivers/usb/misc/adutux.c
drivers/usb/misc/ftdi-elan.c
drivers/usb/misc/trancevibrator.c [new file with mode: 0644]
drivers/usb/net/Kconfig
drivers/usb/net/Makefile
drivers/usb/net/asix.c
drivers/usb/net/cdc_ether.c
drivers/usb/net/kaweth.c
drivers/usb/net/mcs7830.c [new file with mode: 0644]
drivers/usb/net/usbnet.c
drivers/usb/net/usbnet.h
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/airprime.c
drivers/usb/serial/cp2101.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/mos7720.c [new file with mode: 0644]
drivers/usb/serial/mos7840.c
drivers/usb/serial/sierra.c
drivers/usb/storage/unusual_devs.h
include/asm-arm/arch-pxa/pxa-regs.h
include/asm-arm/arch-sa1100/jornada720.h

index b9111a703ce0c37a8a3ad59cc442da283629a0b2..5427bdf225ed0392372ff6ce428dd1e68a2aab83 100644 (file)
@@ -3,20 +3,37 @@ xpad - Linux USB driver for X-Box gamepads
 This is the very first release of a driver for X-Box gamepads.
 Basically, this was hacked away in just a few hours, so don't expect
 miracles.
+
 In particular, there is currently NO support for the rumble pack.
 You won't find many ff-aware linux applications anyway.
 
 
-0. Status
----------
+0. Notes
+--------
+
+Driver updated for kernel 2.6.17.11. (Based on a patch for 2.6.11.4.)
 
-For now, this driver has only been tested on just one Linux-Box.
-This one is running a 2.4.18 kernel with usb-uhci on an amd athlon 600.
+The number of buttons/axes reported varies based on 3 things:
+- if you are using a known controller
+- if you are using a known dance pad
+- if using an unknown device (one not listed below), what you set in the
+  module configuration for "Map D-PAD to buttons rather than axes for unknown
+  pads" (module option dpad_to_buttons)
 
-The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) reports
-8 axes and 10 buttons.
+If you set dpad_to_buttons to 0 and you are using an unknown device (one
+not listed below), the driver will map the directional pad to axes (X/Y),
+if you said N it will map the d-pad to buttons, which is needed for dance
+style games to function correctly.  The default is Y.
+
+dpad_to_buttons has no effect for known pads.
+
+0.1 Normal Controllers
+----------------------
+With a normal controller, the directional pad is mapped to its own X/Y axes.
+The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) will report 8
+axes and 10 buttons.
 
-Alls 8 axes work, though they all have the same range (-32768..32767)
+All 8 axes work, though they all have the same range (-32768..32767)
 and the zero-setting is not correct for the triggers (I don't know if that
 is some limitation of jstest, since the input device setup should be fine. I
 didn't have a look at jstest itself yet).
@@ -30,16 +47,50 @@ in game functionality were OK. However, I find it rather difficult to
 play first person shooters with a pad. Your mileage may vary.
 
 
+0.2 Xbox Dance Pads
+-------------------
+When using a known dance pad, jstest will report 6 axes and 14 buttons.
+
+For dance style pads (like the redoctane pad) several changes
+have been made.  The old driver would map the d-pad to axes, resulting
+in the driver being unable to report when the user was pressing both
+left+right or up+down, making DDR style games unplayable.
+
+Known dance pads automatically map the d-pad to buttons and will work
+correctly out of the box.
+
+If your dance pad is recognized by the driver but is using axes instead
+of buttons, see section 0.3 - Unknown Controllers
+
+I've tested this with Stepmania, and it works quite well.
+
+
+0.3 Unkown Controllers
+----------------------
+If you have an unkown xbox controller, it should work just fine with
+the default settings.
+
+HOWEVER if you have an unknown dance pad not listed below, it will not
+work UNLESS you set "dpad_to_buttons" to 1 in the module configuration.
+
+PLEASE if you have an unkown controller, email Dom <binary1230@yahoo.com> with
+a dump from /proc/bus/usb and a description of the pad (manufacturer, country,
+whether it is a dance pad or normal controller) so that we can add your pad
+to the list of supported devices, ensuring that it will work out of the
+box in the future.
+
+
 1. USB adapter
 --------------
 
 Before you can actually use the driver, you need to get yourself an
-adapter cable to connect the X-Box controller to your Linux-Box.
+adapter cable to connect the X-Box controller to your Linux-Box. You
+can buy these online fairly cheap, or build your own.
 
-Such a cable is pretty easy to build. The Controller itself is a USB compound
-device (a hub with three ports for two expansion slots and the controller
-device) with the only difference in a nonstandard connector (5 pins vs. 4 on
-standard USB connector).
+Such a cable is pretty easy to build. The Controller itself is a USB
+compound device (a hub with three ports for two expansion slots and
+the controller device) with the only difference in a nonstandard connector
+(5 pins vs. 4 on standard USB connector).
 
 You just need to solder a USB connector onto the cable and keep the
 yellow wire unconnected. The other pins have the same order on both
@@ -51,36 +102,36 @@ original one. You can buy an extension cable and cut that instead. That way,
 you can still use the controller with your X-Box, if you have one ;)
 
 
-2. driver installation
+2. Driver Installation
 ----------------------
 
 Once you have the adapter cable and the controller is connected, you need
 to load your USB subsystem and should cat /proc/bus/usb/devices.
 There should be an entry like the one at the end [4].
 
-Currently (as of version 0.0.4), the following three devices are included:
+Currently (as of version 0.0.6), the following devices are included:
  original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202
+ smaller  Microsoft XBOX controller (US), vendor=0x045e, product=0x0289
  original Microsoft XBOX controller (Japan), vendor=0x045e, product=0x0285
  InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a
+ RedOctane Xbox Dance Pad (US), vendor=0x0c12, product=0x8809
 
-If you have another controller that is not listed above and is not recognized
-by the driver, please drop me a line with the appropriate info (that is, include
-the name, vendor and product ID, as well as the country where you bought it;
-sending the whole dump out of /proc/bus/usb/devices along would be even better).
+The driver should work with xbox pads not listed above as well, however
+you will need to do something extra for dance pads to work.
 
-In theory, the driver should work with other controllers than mine
-(InterAct PowerPad pro, bought in Germany) just fine, but I cannot test this
-for I only have this one controller.
+If you have a controller not listed above, see 0.3 - Unknown Controllers
 
 If you compiled and installed the driver, test the functionality:
 > modprobe xpad
 > modprobe joydev
 > jstest /dev/js0
 
-There should be a single line showing 18 inputs (8 axes, 10 buttons), and
-it's values should change if you move the sticks and push the buttons.
+If you're using a normal controller, there should be a single line showing
+18 inputs (8 axes, 10 buttons), and its values should change if you move
+the sticks and push the buttons.  If you're using a dance pad, it should
+show 20 inputs (6 axes, 14 buttons).
 
-It works? Voila, your done ;)
+It works? Voila, you're done ;)
 
 
 3. Thanks
@@ -111,6 +162,22 @@ I:  If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=(none)
 E:  Ad=81(I) Atr=03(Int.) MxPS=  32 Ivl= 10ms
 E:  Ad=02(O) Atr=03(Int.) MxPS=  32 Ivl= 10ms
 
+5. /proc/bus/usb/devices - dump from Redoctane Xbox Dance Pad (US):
+
+T:  Bus=01 Lev=02 Prnt=09 Port=00 Cnt=01 Dev#= 10 Spd=12  MxCh= 0
+D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0c12 ProdID=8809 Rev= 0.01
+S:  Product=XBOX DDR
+C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
+I:  If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=xpad
+E:  Ad=82(I) Atr=03(Int.) MxPS=  32 Ivl=4ms
+E:  Ad=02(O) Atr=03(Int.) MxPS=  32 Ivl=4ms
+
 -- 
 Marko Friedemann <mfr@bmx-chemnitz.de>
 2002-07-16
+ - original doc
+
+Dominic Cerquetti <binary1230@yahoo.com>
+2005-03-19
+ - added stuff for dance pads, new d-pad->axes mappings
index fa5d4976f514e6b8469813452da1c79b7a10527f..1463330ed8ee6b441991f9ca801194f644499edf 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/irq.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
index a6f14801872d3aa73f75b26dd2d4bb31d45f4f7b..9ee63834e6031839a7776492adaa734d5a27347b 100644 (file)
@@ -133,11 +133,13 @@ static void ixdp2400_pci_postinit(void)
        struct pci_dev *dev;
 
        if (ixdp2x00_master_npu()) {
-               dev = pci_find_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
+               dev = pci_get_bus_and_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
                pci_remove_bus_device(dev);
+               pci_dev_put(dev)
        } else {
-               dev = pci_find_slot(1, IXDP2400_MASTER_ENET_DEVFN);
+               dev = pci_get_bus_and_slot(1, IXDP2400_MASTER_ENET_DEVFN);
                pci_remove_bus_device(dev);
+               pci_dev_put(dev)
 
                ixdp2x00_slave_pci_postinit();
        }
index 91d36d91dac03f501a4a3c4377a9802ac13d7082..70d247f09a7ecebe5451f4290efdea4c362b0bbb 100644 (file)
@@ -261,14 +261,16 @@ int __init ixdp2800_pci_init(void)
 
                pci_common_init(&ixdp2800_pci);
                if (ixdp2x00_master_npu()) {
-                       dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
+                       dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
                        pci_remove_bus_device(dev);
+                       pci_dev_put(dev);
 
                        ixdp2800_master_enable_slave();
                        ixdp2800_master_wait_for_slave_bus_scan();
                } else {
-                       dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN);
+                       dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN);
                        pci_remove_bus_device(dev);
+                       pci_dev_put(dev);
                }
        }
 
index af48cb52dfc47b48378308e37c2c41c9b542f520..aa2655092d2dc728805609969a7bbf43331e4ef8 100644 (file)
@@ -241,11 +241,14 @@ void ixdp2x00_slave_pci_postinit(void)
        /*
         * Remove PMC device is there is one
         */
-       if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN)))
+       if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) {
                pci_remove_bus_device(dev);
+               pci_dev_put(dev);
+       }
 
-       dev = pci_find_slot(0, IXDP2X00_21555_DEVFN);
+       dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN);
        pci_remove_bus_device(dev);
+       pci_dev_put(dev);
 }
 
 /**************************************************************************
index ee80d62119d353d61e0fa48db55ff21c591fc550..142c33c3dff57ab4233ef0b4db002c12906c33a3 100644 (file)
@@ -397,7 +397,7 @@ static void lubbock_mmc_poll(unsigned long data)
        if (LUB_IRQ_SET_CLR & (1 << 0))
                mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE);
        else {
-               (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data, NULL);
+               (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data);
                enable_irq(LUBBOCK_SD_IRQ);
        }
 }
index 639597729932e5ce821569f03fcd19184b4515fc..90a4130114a61dcc555139359a3848e1d845f288 100644 (file)
@@ -82,6 +82,14 @@ static struct sdram_params sdram_tbl[] __initdata = {
                .twr            = 9,
                .refresh        = 64000,
                .cas_latency    = 3,
+       }, {    /* Samsung K4S281632B-1H */
+               .name           = "K4S281632b-1H",
+               .rows           = 12,
+               .tck            = 10,
+               .trp            = 20,
+               .twr            = 10,
+               .refresh        = 64000,
+               .cas_latency    = 3,
        }, {    /* Samsung KM416S4030CT */
                .name           = "KM416S4030CT",
                .rows           = 13,
@@ -366,6 +374,8 @@ static int __init sa1110_clk_init(void)
 
                if (machine_is_h3100())
                        name = "KM416S4030CT";
+               if (machine_is_jornada720())
+                       name = "K4S281632B-1H";
        }
 
        sdram = sa1110_find_sdram(name);
index 7899d3ca75a367da1b3a61958668514900122d77..7c3289c2acd7d4b2add8364c502b368ac9e88d9e 100644 (file)
@@ -20,7 +20,8 @@
 #include <linux/sched.h>
 #include <linux/oprofile.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
+
 #include <asm/system.h>
 
 #include "op_counter.h"
index b02af1d740fab56b1f28c7525f7ac97f3006829f..579c69ae9ff78ac47d3b2e01b2830f6da88d80c2 100644 (file)
@@ -4,7 +4,7 @@
 #
 # Up to date versions of this file can be obtained from:
 #
-#   http://www.arm.linux.org.uk/developer/machines/?action=download
+#   http://www.arm.linux.org.uk/developer/machines/download.php
 #
 # Please do not send patches to this file; it is automatically generated!
 # To add an entry into this database, please see Documentation/arm/README,
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Sat Sep 23 13:20:43 2006
+# Last update: Mon Oct 16 21:13:36 2006
 #
 # machine_is_xxx       CONFIG_xxxx             MACH_TYPE_xxx           number
 #
@@ -1157,3 +1157,17 @@ adsturboxb               MACH_ADSTURBOXB         ADSTURBOXB              1143
 oti4110                        MACH_OTI4110            OTI4110                 1144
 hme_pxa                        MACH_HME_PXA            HME_PXA                 1145
 deisterdca             MACH_DEISTERDCA         DEISTERDCA              1146
+ces_ssem2              MACH_CES_SSEM2          CES_SSEM2               1147
+ces_mtr                        MACH_CES_MTR            CES_MTR                 1148
+tds_avng_sbc           MACH_TDS_AVNG_SBC       TDS_AVNG_SBC            1149
+everest                        MACH_EVEREST            EVEREST                 1150
+pnx4010                        MACH_PNX4010            PNX4010                 1151
+oxnas                  MACH_OXNAS              OXNAS                   1152
+fiori                  MACH_FIORI              FIORI                   1153
+ml1200                 MACH_ML1200             ML1200                  1154
+cactus                 MACH_CACTUS             CACTUS                  1155
+nb2xxx                 MACH_NB2XXX             NB2XXX                  1156
+hw6900                 MACH_HW6900             HW6900                  1157
+cdcs_quoll             MACH_CDCS_QUOLL         CDCS_QUOLL              1158
+quicksilver            MACH_QUICKSILVER        QUICKSILVER             1159
+uplat926               MACH_UPLAT926           UPLAT926                1160
index 9431e967aa455000e218dddc99681518418cebe8..2f96610a83e961fc3e6a539c09aac98e9e39bb56 100644 (file)
@@ -289,6 +289,13 @@ endmenu
 
 source "fs/Kconfig"
 
+menu "Instrumentation Support"
+       depends on EXPERIMENTAL
+
+source "arch/sparc/oprofile/Kconfig"
+
+endmenu
+
 source "arch/sparc/Kconfig.debug"
 
 source "security/Kconfig"
index 4cdbb2d59ed0a3e04c5e1d10a5bcf308c8ee7f22..f33c3817f01446810095d86727f79ad48eaa81ee 100644 (file)
@@ -30,6 +30,8 @@ HEAD_Y := $(head-y)
 core-y += arch/sparc/kernel/ arch/sparc/mm/ arch/sparc/math-emu/
 libs-y += arch/sparc/prom/ arch/sparc/lib/
 
+drivers-$(CONFIG_OPROFILE)     += arch/sparc/oprofile/
+
 # Export what is needed by arch/sparc/boot/Makefile
 # Renaming is done to avoid confusing pattern matching rules in 2.5.45 (multy-)
 INIT_Y         := $(patsubst %/, %/built-in.o, $(init-y))
index b3b6680a2a30171483670780b5f64a0851c8666d..c8cb211b90728741877f0326a96803c37ba07527 100644 (file)
@@ -351,7 +351,7 @@ void handler_irq(int irq, struct pt_regs * regs)
 }
 
 #ifdef CONFIG_BLK_DEV_FD
-extern void floppy_interrupt(int irq, void *dev_id)
+extern void floppy_interrupt(int irq, void *dev_id);
 
 void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
index f5ee1ac834bcf38c58de7f799d5054e734507fa1..383526ad94fccb61f9176a51233bcce62d4c5d3a 100644 (file)
@@ -103,7 +103,6 @@ void prom_sync_me(void)
 
 unsigned int boot_flags __initdata = 0;
 #define BOOTME_DEBUG  0x1
-#define BOOTME_SINGLE 0x2
 
 /* Exported for mm/init.c:paging_init. */
 unsigned long cmdline_memory_size __initdata = 0;
@@ -132,7 +131,6 @@ static void __init process_switch(char c)
                boot_flags |= BOOTME_DEBUG;
                break;
        case 's':
-               boot_flags |= BOOTME_SINGLE;
                break;
        case 'h':
                prom_printf("boot_flags_init: Halt!\n");
index 7dcd1a16c6e4213167c0ac8db3a6759de6a05a9e..6c7aa51b590fd5c7d0d10d457698d9c9146a157b 100644 (file)
@@ -95,6 +95,8 @@ unsigned long profile_pc(struct pt_regs *regs)
        return pc;
 }
 
+EXPORT_SYMBOL(profile_pc);
+
 __volatile__ unsigned int *master_l10_counter;
 __volatile__ unsigned int *master_l10_limit;
 
diff --git a/arch/sparc/oprofile/Kconfig b/arch/sparc/oprofile/Kconfig
new file mode 100644 (file)
index 0000000..d8a8408
--- /dev/null
@@ -0,0 +1,17 @@
+config PROFILING
+       bool "Profiling support (EXPERIMENTAL)"
+       help
+         Say Y here to enable the extended profiling support mechanisms used
+         by profilers such as OProfile.
+         
+
+config OPROFILE
+       tristate "OProfile system profiling (EXPERIMENTAL)"
+       depends on PROFILING
+       help
+         OProfile is a profiling system capable of profiling the
+         whole system, include the kernel, kernel modules, libraries,
+         and applications.
+
+         If unsure, say N.
+
diff --git a/arch/sparc/oprofile/Makefile b/arch/sparc/oprofile/Makefile
new file mode 100644 (file)
index 0000000..e9feca1
--- /dev/null
@@ -0,0 +1,9 @@
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
+               oprof.o cpu_buffer.o buffer_sync.o \
+               event_buffer.o oprofile_files.o \
+               oprofilefs.o oprofile_stats.o \
+               timer_int.o )
+
+oprofile-y                             := $(DRIVER_OBJS) init.o
diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c
new file mode 100644 (file)
index 0000000..9ab815b
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * @file init.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/oprofile.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+int __init oprofile_arch_init(struct oprofile_operations * ops)
+{
+       return -ENODEV;
+}
+
+
+void oprofile_arch_exit(void)
+{
+}
index dcae559879ae692b6e713e311d844880ffb72ea6..2f4612fa81f274e5b61982c350c69f6654118bb7 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc1
-# Thu Oct  5 02:08:41 2006
+# Linux kernel version: 2.6.19-rc2
+# Tue Oct 17 19:29:20 2006
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -217,6 +217,7 @@ CONFIG_INET6_XFRM_MODE_TRANSPORT=m
 CONFIG_INET6_XFRM_MODE_TUNNEL=m
 CONFIG_INET6_XFRM_MODE_BEET=m
 # CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
 CONFIG_IPV6_TUNNEL=m
 # CONFIG_IPV6_SUBTREES is not set
 # CONFIG_IPV6_MULTIPLE_TABLES is not set
@@ -333,6 +334,12 @@ CONFIG_CDROM_PKTCDVD_BUFFERS=8
 CONFIG_CDROM_PKTCDVD_WCACHE=y
 CONFIG_ATA_OVER_ETH=m
 
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
 #
 # ATA/ATAPI/MFM/RLL support
 #
@@ -728,7 +735,6 @@ CONFIG_RTC=y
 # TPM devices
 #
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
 
 #
 # I2C support
@@ -841,11 +847,6 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
-#
-# Misc devices
-#
-# CONFIG_TIFM_CORE is not set
-
 #
 # Multimedia devices
 #
@@ -1104,7 +1105,6 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_TRANCEVIBRATOR is not set
 
 #
 # USB Imaging devices
@@ -1150,6 +1150,7 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_APPLEDISPLAY is not set
 # CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_TEST is not set
 
 #
@@ -1234,6 +1235,7 @@ CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4DEV_FS is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
@@ -1361,10 +1363,6 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
 
-#
-# Distributed Lock Manager
-#
-
 #
 # Instrumentation Support
 #
@@ -1399,6 +1397,7 @@ CONFIG_DEBUG_FS=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_UNWIND_INFO is not set
 CONFIG_FORCED_INLINING=y
+# CONFIG_HEADERS_CHECK is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_LKDTM is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
index 7a59cc72c844c438188f5fef41bb4adcc08ea523..827ae30aa4971e5306e1f8c0ed6db494e65b71ec 100644 (file)
@@ -330,19 +330,6 @@ __init get_device_resource(struct linux_prom_pci_registers *ap,
        return res;
 }
 
-static int __init pdev_resource_collisions_expected(struct pci_dev *pdev)
-{
-       if (pdev->vendor != PCI_VENDOR_ID_SUN)
-               return 0;
-
-       if (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS ||
-           pdev->device == PCI_DEVICE_ID_SUN_RIO_1394 ||
-           pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
-               return 1;
-
-       return 0;
-}
-
 static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
                                           struct pci_dev *pdev)
 {
@@ -400,19 +387,23 @@ static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
                pbm->parent->resource_adjust(pdev, res, root);
 
                if (request_resource(root, res) < 0) {
+                       int rnum;
+
                        /* OK, there is some conflict.  But this is fine
                         * since we'll reassign it in the fixup pass.
                         *
-                        * We notify the user that OBP made an error if it
-                        * is a case we don't expect.
+                        * Do not print the warning for ROM resources
+                        * as such a conflict is quite common and
+                        * harmless as the ROM bar is disabled.
                         */
-                       if (!pdev_resource_collisions_expected(pdev)) {
-                               printk(KERN_ERR "PCI: Address space collision on region %ld "
+                       rnum = (res - &pdev->resource[0]);
+                       if (rnum != PCI_ROM_RESOURCE)
+                               printk(KERN_ERR "PCI: Resource collision, "
+                                      "region %d "
                                       "[%016lx:%016lx] of device %s\n",
-                                      (res - &pdev->resource[0]),
+                                      rnum,
                                       res->start, res->end,
                                       pci_name(pdev));
-                       }
                }
        }
 }
index 6ec569828c29c46371055b9f17ed0d83d8cf1a22..de7f7850a844d72f70445b922a023edfac1af40d 100644 (file)
@@ -1196,7 +1196,7 @@ static void pbm_register_toplevel_resources(struct pci_controller_info *p,
                                            &pbm->mem_space);
 }
 
-static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_begin)
+static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end)
 {
        struct pci_pbm_info *pbm;
        struct device_node *node;
@@ -1261,6 +1261,8 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp
                node = node->sibling;
        }
        if (simbas_found == 0) {
+               struct resource *rp;
+
                /* No APBs underneath, probably this is a hummingbird
                 * system.
                 */
@@ -1302,8 +1304,10 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp
                pbm->io_space.end   = pbm->io_space.start + (1UL << 24) - 1UL;
                pbm->io_space.flags = IORESOURCE_IO;
 
-               pbm->mem_space.start = p->pbm_A.controller_regs + SABRE_MEMSPACE;
-               pbm->mem_space.end   = pbm->mem_space.start + (unsigned long)dma_begin - 1UL;
+               pbm->mem_space.start =
+                       (p->pbm_A.controller_regs + SABRE_MEMSPACE);
+               pbm->mem_space.end =
+                       (pbm->mem_space.start + ((1UL << 32UL) - 1UL));
                pbm->mem_space.flags = IORESOURCE_MEM;
 
                if (request_resource(&ioport_resource, &pbm->io_space) < 0) {
@@ -1315,6 +1319,17 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp
                        prom_halt();
                }
 
+               rp = kmalloc(sizeof(*rp), GFP_KERNEL);
+               if (!rp) {
+                       prom_printf("Cannot allocate IOMMU resource.\n");
+                       prom_halt();
+               }
+               rp->name = "IOMMU";
+               rp->start = pbm->mem_space.start + (unsigned long) dma_start;
+               rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL;
+               rp->flags = IORESOURCE_BUSY;
+               request_resource(&pbm->mem_space, rp);
+
                pci_register_legacy_regions(&pbm->io_space,
                                            &pbm->mem_space);
        }
@@ -1450,5 +1465,5 @@ void sabre_init(struct device_node *dp, char *model_name)
        /*
         * Look for APB underneath.
         */
-       sabre_pbm_init(p, dp, vdma[0]);
+       sabre_pbm_init(p, dp, vdma[0], vdma[1]);
 }
index cc8ad480a204152256f97c8b44e15f3f3144c6b4..bf033b31d4376341a8cce56b9ec77e9127f6986b 100644 (file)
@@ -74,7 +74,6 @@ prom_console_write(struct console *con, const char *s, unsigned n)
 
 unsigned int boot_flags = 0;
 #define BOOTME_DEBUG  0x1
-#define BOOTME_SINGLE 0x2
 
 /* Exported for mm/init.c:paging_init. */
 unsigned long cmdline_memory_size = 0;
@@ -102,7 +101,6 @@ static void __init process_switch(char c)
                boot_flags |= BOOTME_DEBUG;
                break;
        case 's':
-               boot_flags |= BOOTME_SINGLE;
                break;
        case 'h':
                prom_printf("boot_flags_init: Halt!\n");
index dc1ebeac35c7d74b2e480b3362d5742a2f2f1d07..9e7bd94b958ad528b28b0d06e2bd7f02e4855c76 100644 (file)
@@ -1243,7 +1243,7 @@ static struct pci_driver c2_pci_driver = {
 
 static int __init c2_init_module(void)
 {
-       return pci_module_init(&c2_pci_driver);
+       return pci_register_driver(&c2_pci_driver);
 }
 
 static void __exit c2_exit_module(void)
index e37c5688c2146c969a609cc9a913d01319b86700..30409e179606e0b5d05609bf96b8b671910ac558 100644 (file)
@@ -150,8 +150,8 @@ static int c2_rnic_query(struct c2_dev *c2dev, struct ib_device_attr *props)
            (struct c2wr_rnic_query_rep *) (unsigned long) (vq_req->reply_msg);
        if (!reply)
                err = -ENOMEM;
-
-       err = c2_errno(reply);
+       else
+               err = c2_errno(reply);
        if (err)
                goto bail2;
 
index 29958b6e0214a672905bab6dc61a50e7f8a021d0..28c087b824c2846c7d6e971e59359295618587b0 100644 (file)
@@ -67,19 +67,54 @@ static struct file_operations diag_file_ops = {
        .release = ipath_diag_release
 };
 
+static ssize_t ipath_diagpkt_write(struct file *fp,
+                                  const char __user *data,
+                                  size_t count, loff_t *off);
+
+static struct file_operations diagpkt_file_ops = {
+       .owner = THIS_MODULE,
+       .write = ipath_diagpkt_write,
+};
+
+static atomic_t diagpkt_count = ATOMIC_INIT(0);
+static struct cdev *diagpkt_cdev;
+static struct class_device *diagpkt_class_dev;
+
 int ipath_diag_add(struct ipath_devdata *dd)
 {
        char name[16];
+       int ret = 0;
+
+       if (atomic_inc_return(&diagpkt_count) == 1) {
+               ret = ipath_cdev_init(IPATH_DIAGPKT_MINOR,
+                                     "ipath_diagpkt", &diagpkt_file_ops,
+                                     &diagpkt_cdev, &diagpkt_class_dev);
+
+               if (ret) {
+                       ipath_dev_err(dd, "Couldn't create ipath_diagpkt "
+                                     "device: %d", ret);
+                       goto done;
+               }
+       }
 
        snprintf(name, sizeof(name), "ipath_diag%d", dd->ipath_unit);
 
-       return ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
-                              &diag_file_ops, &dd->diag_cdev,
-                              &dd->diag_class_dev);
+       ret = ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
+                             &diag_file_ops, &dd->diag_cdev,
+                             &dd->diag_class_dev);
+       if (ret)
+               ipath_dev_err(dd, "Couldn't create %s device: %d",
+                             name, ret);
+
+done:
+       return ret;
 }
 
 void ipath_diag_remove(struct ipath_devdata *dd)
 {
+       if (atomic_dec_and_test(&diagpkt_count))
+               ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev);
+
        ipath_cdev_cleanup(&dd->diag_cdev, &dd->diag_class_dev);
 }
 
@@ -275,30 +310,6 @@ bail:
        return ret;
 }
 
-static ssize_t ipath_diagpkt_write(struct file *fp,
-                                  const char __user *data,
-                                  size_t count, loff_t *off);
-
-static struct file_operations diagpkt_file_ops = {
-       .owner = THIS_MODULE,
-       .write = ipath_diagpkt_write,
-};
-
-static struct cdev *diagpkt_cdev;
-static struct class_device *diagpkt_class_dev;
-
-int __init ipath_diagpkt_add(void)
-{
-       return ipath_cdev_init(IPATH_DIAGPKT_MINOR,
-                              "ipath_diagpkt", &diagpkt_file_ops,
-                              &diagpkt_cdev, &diagpkt_class_dev);
-}
-
-void __exit ipath_diagpkt_remove(void)
-{
-       ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev);
-}
-
 /**
  * ipath_diagpkt_write - write an IB packet
  * @fp: the diag data device file pointer
index 12cefa658f3ba888f808c79b902f9fb018fb380c..b4ffaa7bcbb752467591e384d052041fcdf1b2f4 100644 (file)
@@ -2005,18 +2005,8 @@ static int __init infinipath_init(void)
                goto bail_group;
        }
 
-       ret = ipath_diagpkt_add();
-       if (ret < 0) {
-               printk(KERN_ERR IPATH_DRV_NAME ": Unable to create "
-                      "diag data device: error %d\n", -ret);
-               goto bail_ipathfs;
-       }
-
        goto bail;
 
-bail_ipathfs:
-       ipath_exit_ipathfs();
-
 bail_group:
        ipath_driver_remove_group(&ipath_driver.driver);
 
index 7c436697d0e43df1be4e69074cdcc208737cca6a..06d5020a2f60625882920c1b52c74d680fa15660 100644 (file)
@@ -869,9 +869,6 @@ int ipath_device_create_group(struct device *, struct ipath_devdata *);
 void ipath_device_remove_group(struct device *, struct ipath_devdata *);
 int ipath_expose_reset(struct device *);
 
-int ipath_diagpkt_add(void);
-void ipath_diagpkt_remove(void);
-
 int ipath_init_ipathfs(void);
 void ipath_exit_ipathfs(void);
 int ipathfs_add_device(struct ipath_devdata *);
index e393681ba7d46a1988508c3f5d25e27b2cd4261d..149b3690123968ced42384ca1173be972ef710be 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/init.h>
 #include <linux/hardirq.h>
 
+#include <asm/io.h>
+
 #include <rdma/ib_pack.h>
 
 #include "mthca_dev.h"
@@ -210,6 +212,11 @@ static inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq,
                mthca_write64(doorbell,
                              dev->kar + MTHCA_CQ_DOORBELL,
                              MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+               /*
+                * Make sure doorbells don't leak out of CQ spinlock
+                * and reach the HCA out of order:
+                */
+               mmiowb();
        }
 }
 
index 5e5c58b9920b5c3d53b6d0a61a3afcaee037e281..6a7822e0fc19a94ca67fc306d5207aabdc865466 100644 (file)
@@ -39,6 +39,8 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 
+#include <asm/io.h>
+
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_cache.h>
 #include <rdma/ib_pack.h>
@@ -1732,6 +1734,11 @@ out:
                mthca_write64(doorbell,
                              dev->kar + MTHCA_SEND_DOORBELL,
                              MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+               /*
+                * Make sure doorbells don't leak out of SQ spinlock
+                * and reach the HCA out of order:
+                */
+               mmiowb();
        }
 
        qp->sq.next_ind = ind;
@@ -1851,6 +1858,12 @@ out:
        qp->rq.next_ind = ind;
        qp->rq.head    += nreq;
 
+       /*
+        * Make sure doorbells don't leak out of RQ spinlock and reach
+        * the HCA out of order:
+        */
+       mmiowb();
+
        spin_unlock_irqrestore(&qp->rq.lock, flags);
        return err;
 }
@@ -2112,6 +2125,12 @@ out:
                              MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
        }
 
+       /*
+        * Make sure doorbells don't leak out of SQ spinlock and reach
+        * the HCA out of order:
+        */
+       mmiowb();
+
        spin_unlock_irqrestore(&qp->sq.lock, flags);
        return err;
 }
index 92a72f5215286493250283b89b7aed2ab096af9a..f5d7677d107969ee59b68b815d4926d7a5685cbf 100644 (file)
@@ -35,6 +35,8 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 
+#include <asm/io.h>
+
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
 #include "mthca_memfree.h"
@@ -595,6 +597,12 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
                              MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
        }
 
+       /*
+        * Make sure doorbells don't leak out of SRQ spinlock and
+        * reach the HCA out of order:
+        */
+       mmiowb();
+
        spin_unlock_irqrestore(&srq->lock, flags);
        return err;
 }
index cb70970625b5b9f05cd4dbe05d66c312e9cec824..befdd6006b500d093be9036386b491da39496c9b 100644 (file)
@@ -207,7 +207,7 @@ static irqreturn_t corgikbd_interrupt(int irq, void *dev_id)
 static void corgikbd_timer_callback(unsigned long data)
 {
        struct corgikbd *corgikbd_data = (struct corgikbd *) data;
-       corgikbd_scankeyboard(corgikbd_data, NULL);
+       corgikbd_scankeyboard(corgikbd_data);
 }
 
 /*
index fd33c9cc3272ac78972e31dd566c193564e0681f..5788dbc317bba3226266b28e78dc0890fe7125e7 100644 (file)
@@ -186,7 +186,7 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
 static void locomokbd_timer_callback(unsigned long data)
 {
        struct locomokbd *locomokbd = (struct locomokbd *) data;
-       locomokbd_scankeyboard(locomokbd, NULL);
+       locomokbd_scankeyboard(locomokbd);
 }
 
 static int locomokbd_probe(struct locomo_dev *dev)
index 8b18c009e3e027b42889d3ee8d2827263b393ad4..28b2748e82d087bf4255d40c9ecca17f779811d6 100644 (file)
@@ -257,7 +257,7 @@ static void spitzkbd_timer_callback(unsigned long data)
 {
        struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data;
 
-       spitzkbd_scankeyboard(spitzkbd_data, NULL);
+       spitzkbd_scankeyboard(spitzkbd_data);
 }
 
 /*
index ca79b2246195c910509d6b72a4e9104f57419af3..66121f6a89ad1969ad54dab4e9233b9e275d3a0e 100644 (file)
@@ -219,7 +219,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer)
 static void corgi_ts_timer(unsigned long data)
 {
        struct corgi_ts *corgits_data = (struct corgi_ts *) data;
-       ts_interrupt_main(corgits_data, 1, NULL);
+       ts_interrupt_main(corgits_data, 1);
 }
 
 static irqreturn_t ts_interrupt(int irq, void *dev_id)
@@ -237,7 +237,7 @@ static int corgits_suspend(struct platform_device *dev, pm_message_t state)
        if (corgi_ts->pendown) {
                del_timer_sync(&corgi_ts->timer);
                corgi_ts->tc.pressure = 0;
-               new_data(corgi_ts, NULL);
+               new_data(corgi_ts);
                corgi_ts->pendown = 0;
        }
        corgi_ts->power_mode = PWR_MODE_SUSPEND;
index e21ec9b2c706ceb72e92eff05b3ed9b3a8fcf5f9..ba7b8652c5013813808da694801c9c36c6005451 100644 (file)
@@ -1,8 +1,8 @@
 /* This is the Myrinet MCP code for LANai4.x */
 /* Generated by  cat $MYRI_HOME/lib/lanai/mcp4.dat > myri_code4.h */
 
-static unsigned int lanai4_code_off = 0x0000; /* half-word offset */
-static unsigned char lanai4_code[76256] __initdata = {
+static unsigned int __devinitdata lanai4_code_off = 0x0000; /* half-word offset */
+static unsigned char __devinitdata lanai4_code[76256] = {
 0xF2,0x0E,
 0xFE,0x00, 0xC2,0x90, 0x00,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x01,0x4C, 0x97,0x93,
 0xFF,0xFC, 0xE0,0x00, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
@@ -4774,8 +4774,8 @@ static unsigned char lanai4_code[76256] __initdata = {
 
 /* This is the LANai data */
 
-static unsigned int lanai4_data_off = 0x94F0; /* half-word offset */
-static unsigned char lanai4_data[20472] __initdata;
+static unsigned int __devinitdata lanai4_data_off = 0x94F0; /* half-word offset */
+static unsigned char __devinitdata lanai4_data[20472];
 
 
 #ifdef SYMBOL_DEFINES_COMPILED
index 466b484c9fa40dd19dfdd00180f7a3f6c3fceac0..7747bfd99f916a8b084623ba48e00e40a275c8af 100644 (file)
@@ -168,7 +168,7 @@ static int myri_do_handshake(struct myri_eth *mp)
        return 0;
 }
 
-static int myri_load_lanai(struct myri_eth *mp)
+static int __devinit myri_load_lanai(struct myri_eth *mp)
 {
        struct net_device       *dev = mp->dev;
        struct myri_shmem __iomem *shmem = mp->shmem;
@@ -891,7 +891,7 @@ static void dump_eeprom(struct myri_eth *mp)
 }
 #endif
 
-static int __init myri_ether_init(struct sbus_dev *sdev)
+static int __devinit myri_ether_init(struct sbus_dev *sdev)
 {
        static int num;
        static unsigned version_printed;
index 6439b0cef1e4ba9f0124d43eaa196256f1c73095..18f88853e1e583efd38b1f8368dd17ecff873489 100644 (file)
@@ -42,7 +42,7 @@
 #define DRV_RELDATE    "11/24/03"
 #define DRV_AUTHOR     "David S. Miller (davem@redhat.com)"
 
-static char version[] __initdata =
+static char version[] =
        DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
 
 MODULE_VERSION(DRV_VERSION);
index 0d3660c28f7d496840598b908ff909ec753c8c7a..a54e4140683aea238d28e48f50621e801c7d9450 100644 (file)
@@ -5,8 +5,8 @@
  */
 
 #include <linux/kthread.h>
-#include <linux/syscalls.h>
 #include <linux/delay.h>
+#include <linux/kmod.h>
 #include <asm/oplib.h>
 #include <asm/ebus.h>
 
@@ -195,7 +195,7 @@ static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
        printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
 
        shutting_down = 1;
-       if (kernel_execve("/sbin/shutdown", argv, envp) < 0)
+       if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0)
                printk(KERN_CRIT "envctrl: shutdown execution failed\n");
 }
 
index 6b6a855f3795d8cea72822c0b3bb8f5786b83581..fff4660cdf96e34880f7242d0fdecc588c05536a 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/miscdevice.h>
-#include <linux/syscalls.h>
+#include <linux/kmod.h>
 
 #include <asm/ebus.h>
 #include <asm/uaccess.h>
@@ -976,7 +976,7 @@ static void envctrl_do_shutdown(void)
 
        inprog = 1;
        printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");
-       ret = kernel_execve("/sbin/shutdown", argv, envp);
+       ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0);
        if (ret < 0) {
                printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); 
                inprog = 0;  /* unlikely to succeed, but we could try again */
index ed58bb489889acdc85228055351e6753e3b8027f..9b827ceec50125734cd6ef3cafebb6f87949d4fe 100644 (file)
@@ -461,7 +461,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
 
 #define PTI_RESET_LIMIT 400
 
-static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
+static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti)
 {
        struct Scsi_Host *host = qpti->qhost;
        unsigned short csum = 0;
index 1545b30681b4f1b93a3d2f0b6988438d0d69ffc5..19aa84f460182c5dba50deccc3e9684a7d08082e 100644 (file)
@@ -1,5 +1,5 @@
 /* Version 1.31.00 ISP1000 Initiator RISC firmware */
-unsigned short sbus_risc_code01[] __initdata = {
+unsigned short sbus_risc_code01[] __devinitdata = {
        0x0078, 0x1030, 0x0000, 0x2419, 0x0000, 0x12ff, 0x2043, 0x4f50,
        0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932,
        0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749,
@@ -1157,4 +1157,4 @@ unsigned short sbus_risc_code01[] __initdata = {
        0x003c, 0x0040, 0x3415, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x007c,
        0x92a7
 };
-unsigned short sbus_risc_code_length01 = 0x2419;
+unsigned short __devinitdata sbus_risc_code_length01 = 0x2419;
index 97d57cfc343b628fb81f78820c2ad6cea9e5b958..825bf884537a2204ecdd6019093be9f52bfe4e96 100644 (file)
@@ -33,7 +33,6 @@ obj-$(CONFIG_USB_KBTAB)               += input/
 obj-$(CONFIG_USB_MOUSE)                += input/
 obj-$(CONFIG_USB_MTOUCH)       += input/
 obj-$(CONFIG_USB_POWERMATE)    += input/
-obj-$(CONFIG_USB_TRANCEVIBRATOR)+= input/
 obj-$(CONFIG_USB_WACOM)                += input/
 obj-$(CONFIG_USB_XPAD)         += input/
 
@@ -66,6 +65,7 @@ obj-$(CONFIG_USB_PHIDGETSERVO)        += misc/
 obj-$(CONFIG_USB_RIO500)       += misc/
 obj-$(CONFIG_USB_SISUSBVGA)    += misc/
 obj-$(CONFIG_USB_TEST)         += misc/
+obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
 obj-$(CONFIG_USB_USS720)       += misc/
 
 obj-$(CONFIG_USB_ATM)          += atm/
index 3892a9e9aee3941ca48c9b7f4a3c6e9b6aa79f9d..e6565633ba0fa7801fa8687ff0580fbb1c92b879 100644 (file)
@@ -793,6 +793,9 @@ static const struct usb_device_id cxacru_usb_ids[] = {
        { /* V = Conexant                       P = ADSL modem                          */
                USB_DEVICE(0x0572, 0xcb06),     .driver_info = (unsigned long) &cxacru_cb00
        },
+       { /* V = Conexant                       P = ADSL modem (ZTE ZXDSL 852)          */
+               USB_DEVICE(0x0572, 0xcb07),     .driver_info = (unsigned long) &cxacru_cb00
+       },
        { /* V = Olitec                         P = ADSL modem version 2                */
                USB_DEVICE(0x08e3, 0x0100),     .driver_info = (unsigned long) &cxacru_cafe
        },
index 7c7b507af29df72524adf3816f2952aaffbf07ad..c870c804470fb09d9a286764b7fc09b8db415a50 100644 (file)
@@ -55,7 +55,6 @@ static const char speedtch_driver_name[] = "speedtch";
 #define OFFSET_d       9               /* size 4 */
 #define OFFSET_e       13              /* size 1 */
 #define OFFSET_f       14              /* size 1 */
-#define TOTAL          15
 
 #define SIZE_7         1
 #define SIZE_b         8
@@ -79,6 +78,18 @@ static int dl_512_first = DEFAULT_DL_512_FIRST;
 static int enable_isoc = DEFAULT_ENABLE_ISOC;
 static int sw_buffering = DEFAULT_SW_BUFFERING;
 
+#define DEFAULT_B_MAX_DSL      8128
+#define DEFAULT_MODEM_MODE     11
+#define MODEM_OPTION_LENGTH    16
+static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = {
+       0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL;
+static unsigned char ModemMode = DEFAULT_MODEM_MODE;
+static unsigned char ModemOption[MODEM_OPTION_LENGTH];
+static int num_ModemOption;
+
 module_param(altsetting, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(altsetting,
                "Alternative setting for data interface (bulk_default: "
@@ -100,6 +111,17 @@ MODULE_PARM_DESC(sw_buffering,
                 "Enable software buffering (default: "
                 __MODULE_STRING(DEFAULT_SW_BUFFERING) ")");
 
+module_param(BMaxDSL, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(BMaxDSL,
+               "default: " __MODULE_STRING(DEFAULT_B_MAX_DSL));
+
+module_param(ModemMode, byte, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ModemMode,
+               "default: " __MODULE_STRING(DEFAULT_MODEM_MODE));
+
+module_param_array(ModemOption, byte, &num_ModemOption, S_IRUGO);
+MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20");
+
 #define INTERFACE_DATA         1
 #define ENDPOINT_INT           0x81
 #define ENDPOINT_BULK_DATA     0x07
@@ -108,10 +130,17 @@ MODULE_PARM_DESC(sw_buffering,
 
 #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
 
+struct speedtch_params {
+       unsigned int altsetting;
+       unsigned int BMaxDSL;
+       unsigned char ModemMode;
+       unsigned char ModemOption[MODEM_OPTION_LENGTH];
+};
+
 struct speedtch_instance_data {
        struct usbatm_data *usbatm;
 
-       unsigned int altsetting;
+       struct speedtch_params params; /* set in probe, constant afterwards */
 
        struct work_struct status_checker;
 
@@ -123,7 +152,7 @@ struct speedtch_instance_data {
        struct urb *int_urb;
        unsigned char int_data[16];
 
-       unsigned char scratch_buffer[TOTAL];
+       unsigned char scratch_buffer[16];
 };
 
 /***************
@@ -186,6 +215,34 @@ static void speedtch_test_sequence(struct speedtch_instance_data *instance)
                              0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT);
        if (ret < 0)
                usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret);
+
+       /* Extra initialisation in recent drivers - gives higher speeds */
+
+       /* URBext1 */
+       buf[0] = instance->params.ModemMode;
+       ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                             0x01, 0x40, 0x11, 0x00, buf, 1, CTRL_TIMEOUT);
+       if (ret < 0)
+               usb_warn(usbatm, "%s failed on URBext1: %d\n", __func__, ret);
+
+       /* URBext2 */
+       /* This seems to be the one which actually triggers the higher sync
+          rate -- it does require the new firmware too, although it works OK
+          with older firmware */
+       ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                             0x01, 0x40, 0x14, 0x00,
+                             instance->params.ModemOption,
+                             MODEM_OPTION_LENGTH, CTRL_TIMEOUT);
+       if (ret < 0)
+               usb_warn(usbatm, "%s failed on URBext2: %d\n", __func__, ret);
+
+       /* URBext3 */
+       buf[0] = instance->params.BMaxDSL & 0xff;
+       buf[1] = instance->params.BMaxDSL >> 8;
+       ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                             0x01, 0x40, 0x12, 0x00, buf, 2, CTRL_TIMEOUT);
+       if (ret < 0)
+               usb_warn(usbatm, "%s failed on URBext3: %d\n", __func__, ret);
 }
 
 static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
@@ -285,8 +342,8 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
           because we're in our own kernel thread anyway. */
        msleep_interruptible(1000);
 
-       if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) {
-               usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->altsetting, ret);
+       if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) {
+               usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->params.altsetting, ret);
                goto out_free;
        }
 
@@ -372,7 +429,7 @@ static int speedtch_read_status(struct speedtch_instance_data *instance)
        unsigned char *buf = instance->scratch_buffer;
        int ret;
 
-       memset(buf, 0, TOTAL);
+       memset(buf, 0, 16);
 
        ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
                              0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,
@@ -746,17 +803,21 @@ static int speedtch_bind(struct usbatm_data *usbatm,
 
        instance->usbatm = usbatm;
 
-       /* altsetting and enable_isoc may change at any moment, so take a snapshot */
-       instance->altsetting = altsetting;
+       /* module parameters may change at any moment, so take a snapshot */
+       instance->params.altsetting = altsetting;
+       instance->params.BMaxDSL = BMaxDSL;
+       instance->params.ModemMode = ModemMode;
+       memcpy(instance->params.ModemOption, DEFAULT_MODEM_OPTION, MODEM_OPTION_LENGTH);
+       memcpy(instance->params.ModemOption, ModemOption, num_ModemOption);
        use_isoc = enable_isoc;
 
-       if (instance->altsetting)
-               if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) {
-                       usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->altsetting, ret);
-                       instance->altsetting = 0; /* fall back to default */
+       if (instance->params.altsetting)
+               if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) {
+                       usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->params.altsetting, ret);
+                       instance->params.altsetting = 0; /* fall back to default */
                }
 
-       if (!instance->altsetting && use_isoc)
+       if (!instance->params.altsetting && use_isoc)
                if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) {
                        usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret);
                        use_isoc = 0; /* fall back to bulk */
@@ -783,14 +844,14 @@ static int speedtch_bind(struct usbatm_data *usbatm,
                        usb_info(usbatm, "isochronous transfer not supported - using bulk\n");
        }
 
-       if (!use_isoc && !instance->altsetting)
+       if (!use_isoc && !instance->params.altsetting)
                if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) {
                        usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret);
                        goto fail_free;
                }
 
-       if (!instance->altsetting)
-               instance->altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING;
+       if (!instance->params.altsetting)
+               instance->params.altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING;
 
        usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0);
 
index f5434b1cbb1e0bba726cdd8ff3303f42c0d73594..f6b9f7e1f716d5dd05c84b4bf836cfc57212adff 100644 (file)
@@ -68,7 +68,7 @@
 
 #include "usbatm.h"
 
-#define EAGLEUSBVERSION "ueagle 1.3"
+#define EAGLEUSBVERSION "ueagle 1.4"
 
 
 /*
                        dev_dbg(&(usb_dev)->dev, \
                                "[ueagle-atm dbg] %s: " format, \
                                        __FUNCTION__, ##args); \
-       } while (0)
+       } while (0)
 
 #define uea_vdbg(usb_dev, format, args...)     \
        do { \
                if (debug >= 2) \
                        dev_dbg(&(usb_dev)->dev, \
                                "[ueagle-atm vdbg]  " format, ##args); \
-       } while (0)
+       } while (0)
 
 #define uea_enters(usb_dev) \
        uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__)
@@ -218,8 +218,8 @@ enum {
 #define UEA_CHIP_VERSION(x) \
        ((x)->driver_info & 0xf)
 
-#define IS_ISDN(sc) \
-       (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)
+#define IS_ISDN(usb_dev) \
+       (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
 
 #define INS_TO_USBDEV(ins) ins->usb_dev
 
@@ -625,12 +625,12 @@ static int request_dsp(struct uea_softc *sc)
        char *dsp_name;
 
        if (UEA_CHIP_VERSION(sc) == ADI930) {
-               if (IS_ISDN(sc))
+               if (IS_ISDN(sc->usb_dev))
                        dsp_name = FW_DIR "DSP9i.bin";
                else
                        dsp_name = FW_DIR "DSP9p.bin";
        } else {
-               if (IS_ISDN(sc))
+               if (IS_ISDN(sc->usb_dev))
                        dsp_name = FW_DIR "DSPei.bin";
                else
                        dsp_name = FW_DIR "DSPep.bin";
@@ -744,7 +744,7 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc)
 
 static inline int wait_cmv_ack(struct uea_softc *sc)
 {
-       int ret = wait_event_timeout(sc->cmv_ack_wait,
+       int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
                                                   sc->cmv_ack, ACK_TIMEOUT);
        sc->cmv_ack = 0;
 
@@ -885,7 +885,8 @@ static int uea_stat(struct uea_softc *sc)
                break;
 
        case 3:         /* fail ... */
-               uea_info(INS_TO_USBDEV(sc), "modem synchronization failed\n");
+               uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
+                               " (may be try other cmv/dsp)\n");
                return -EAGAIN;
 
        case 4 ... 6:   /* test state */
@@ -913,12 +914,6 @@ static int uea_stat(struct uea_softc *sc)
                        release_firmware(sc->dsp_firm);
                        sc->dsp_firm = NULL;
                }
-
-               ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
-               if (ret < 0)
-                       return ret;
-               uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
-                               sc->stats.phy.firmid);
        }
 
        /* always update it as atm layer could not be init when we switch to
@@ -1033,9 +1028,9 @@ static int request_cmvs(struct uea_softc *sc,
 
        if (cmv_file[sc->modem_index] == NULL) {
                if (UEA_CHIP_VERSION(sc) == ADI930)
-                       file = (IS_ISDN(sc)) ? "CMV9i.bin" : "CMV9p.bin";
+                       file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
                else
-                       file = (IS_ISDN(sc)) ? "CMVei.bin" : "CMVep.bin";
+                       file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
        } else
                file = cmv_file[sc->modem_index];
 
@@ -1131,6 +1126,13 @@ static int uea_start_reset(struct uea_softc *sc)
        if (ret < 0)
                return ret;
 
+       /* Dump firmware version */
+       ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
+       if (ret < 0)
+               return ret;
+       uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+                       sc->stats.phy.firmid);
+
        /* get options */
        ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
        if (ret < 0)
@@ -1147,6 +1149,8 @@ static int uea_start_reset(struct uea_softc *sc)
        /* Enter in R-ACT-REQ */
        ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
        uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+       uea_info(INS_TO_USBDEV(sc), "Modem started, "
+               "waiting synchronization\n");
 out:
        release_firmware(cmvs_fw);
        sc->reset = 0;
@@ -1172,7 +1176,10 @@ static int uea_kthread(void *data)
                if (!ret)
                        ret = uea_stat(sc);
                if (ret != -EAGAIN)
-                       msleep(1000);
+                       msleep_interruptible(1000);
+               if (try_to_freeze())
+                       uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
+                               "please unplug/replug your modem\n");
        }
        uea_leaves(INS_TO_USBDEV(sc));
        return ret;
@@ -1566,6 +1573,7 @@ UEA_ATTR(uscorr, 0);
 UEA_ATTR(dscorr, 0);
 UEA_ATTR(usunc, 0);
 UEA_ATTR(dsunc, 0);
+UEA_ATTR(firmid, 0);
 
 /* Retrieve the device End System Identifier (MAC) */
 
@@ -1597,7 +1605,7 @@ static int uea_heavy(struct usbatm_data *usbatm, struct usb_interface *intf)
 {
        struct uea_softc *sc = usbatm->driver_data;
 
-       wait_event(sc->sync_q, IS_OPERATIONAL(sc));
+       wait_event_interruptible(sc->sync_q, IS_OPERATIONAL(sc));
 
        return 0;
 
@@ -1639,16 +1647,13 @@ static struct attribute *attrs[] = {
        &dev_attr_stat_dscorr.attr,
        &dev_attr_stat_usunc.attr,
        &dev_attr_stat_dsunc.attr,
+       &dev_attr_stat_firmid.attr,
+       NULL,
 };
 static struct attribute_group attr_grp = {
        .attrs = attrs,
 };
 
-static int create_fs_entries(struct usb_interface *intf)
-{
-       return sysfs_create_group(&intf->dev.kobj, &attr_grp);
-}
-
 static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
                   const struct usb_device_id *id)
 {
@@ -1708,31 +1713,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
                }
        }
 
+       ret = sysfs_create_group(&intf->dev.kobj, &attr_grp);
+       if (ret < 0)
+               goto error;
+
        ret = uea_boot(sc);
-       if (ret < 0) {
-               kfree(sc);
-               return ret;
-       }
+       if (ret < 0)
+               goto error;
 
-       ret = create_fs_entries(intf);
-       if (ret) {
-               uea_stop(sc);
-               kfree(sc);
-               return ret;
-       }
        return 0;
-}
-
-static void destroy_fs_entries(struct usb_interface *intf)
-{
-       sysfs_remove_group(&intf->dev.kobj, &attr_grp);
+error:
+       kfree(sc);
+       return ret;
 }
 
 static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
 {
        struct uea_softc *sc = usbatm->driver_data;
 
-       destroy_fs_entries(intf);
+       sysfs_remove_group(&intf->dev.kobj, &attr_grp);
        uea_stop(sc);
        kfree(sc);
 }
@@ -1753,10 +1752,10 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
        struct usb_device *usb = interface_to_usbdev(intf);
 
        uea_enters(usb);
-       uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s\n",
+       uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
               le16_to_cpu(usb->descriptor.idVendor),
               le16_to_cpu(usb->descriptor.idProduct),
-              chip_name[UEA_CHIP_VERSION(id)]);
+              chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
 
        usb_reset_device(usb);
 
index 309073f6433a73d02b8355e4605e0ab8187a3a87..ec63b0ee07437312f8c9abc6a4f3dfbe057d7d70 100644 (file)
@@ -1001,6 +1001,7 @@ static int usbatm_do_heavy_init(void *arg)
 
        daemonize(instance->driver->driver_name);
        allow_signal(SIGTERM);
+       instance->thread_pid = current->pid;
 
        complete(&instance->thread_started);
 
@@ -1025,10 +1026,6 @@ static int usbatm_heavy_init(struct usbatm_data *instance)
                return ret;
        }
 
-       mutex_lock(&instance->serialize);
-       instance->thread_pid = ret;
-       mutex_unlock(&instance->serialize);
-
        wait_for_completion(&instance->thread_started);
 
        return 0;
index ec4d1d756725001e7296361b611d5c744317499d..9a9012fd284b48668e7feb7d46b32bcfd97810f2 100644 (file)
@@ -325,7 +325,7 @@ static void acm_rx_tasklet(unsigned long _acm)
        struct acm_rb *buf;
        struct tty_struct *tty = acm->tty;
        struct acm_ru *rcv;
-       //unsigned long flags;
+       unsigned long flags;
        int i = 0;
        dbg("Entering acm_rx_tasklet");
 
@@ -333,15 +333,15 @@ static void acm_rx_tasklet(unsigned long _acm)
                return;
 
 next_buffer:
-       spin_lock(&acm->read_lock);
+       spin_lock_irqsave(&acm->read_lock, flags);
        if (list_empty(&acm->filled_read_bufs)) {
-               spin_unlock(&acm->read_lock);
+               spin_unlock_irqrestore(&acm->read_lock, flags);
                goto urbs;
        }
        buf = list_entry(acm->filled_read_bufs.next,
                         struct acm_rb, list);
        list_del(&buf->list);
-       spin_unlock(&acm->read_lock);
+       spin_unlock_irqrestore(&acm->read_lock, flags);
 
        dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
 
@@ -356,29 +356,29 @@ next_buffer:
                memmove(buf->base, buf->base + i, buf->size - i);
                buf->size -= i;
                spin_unlock(&acm->throttle_lock);
-               spin_lock(&acm->read_lock);
+               spin_lock_irqsave(&acm->read_lock, flags);
                list_add(&buf->list, &acm->filled_read_bufs);
-               spin_unlock(&acm->read_lock);
+               spin_unlock_irqrestore(&acm->read_lock, flags);
                return;
        }
        spin_unlock(&acm->throttle_lock);
 
-       spin_lock(&acm->read_lock);
+       spin_lock_irqsave(&acm->read_lock, flags);
        list_add(&buf->list, &acm->spare_read_bufs);
-       spin_unlock(&acm->read_lock);
+       spin_unlock_irqrestore(&acm->read_lock, flags);
        goto next_buffer;
 
 urbs:
        while (!list_empty(&acm->spare_read_bufs)) {
-               spin_lock(&acm->read_lock);
+               spin_lock_irqsave(&acm->read_lock, flags);
                if (list_empty(&acm->spare_read_urbs)) {
-                       spin_unlock(&acm->read_lock);
+                       spin_unlock_irqrestore(&acm->read_lock, flags);
                        return;
                }
                rcv = list_entry(acm->spare_read_urbs.next,
                                 struct acm_ru, list);
                list_del(&rcv->list);
-               spin_unlock(&acm->read_lock);
+               spin_unlock_irqrestore(&acm->read_lock, flags);
 
                buf = list_entry(acm->spare_read_bufs.next,
                                 struct acm_rb, list);
@@ -400,9 +400,9 @@ urbs:
                   free-urbs-pool and resubmited ASAP */
                if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
                        list_add(&buf->list, &acm->spare_read_bufs);
-                       spin_lock(&acm->read_lock);
+                       spin_lock_irqsave(&acm->read_lock, flags);
                        list_add(&rcv->list, &acm->spare_read_urbs);
-                       spin_unlock(&acm->read_lock);
+                       spin_unlock_irqrestore(&acm->read_lock, flags);
                        return;
                }
        }
@@ -1083,6 +1083,9 @@ static struct usb_device_id acm_ids[] = {
        { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
        .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
        },
+       { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
+       .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+       },
        { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
        .driver_info = SINGLE_RX_URB, /* firmware bug */
        },
index a161d70e1e42c3af7800581ec182333739f1ef27..809d465eb25726dfd0806869f99f4725f8089c43 100644 (file)
@@ -154,6 +154,7 @@ struct usblp {
        unsigned char           used;                   /* True if open */
        unsigned char           present;                /* True if not disconnected */
        unsigned char           bidir;                  /* interface is bidirectional */
+       unsigned char           sleeping;               /* interface is suspended */
        unsigned char           *device_id_string;      /* IEEE 1284 DEVICE ID string (ptr) */
                                                        /* first 2 bytes are (big-endian) length */
 };
@@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usblp) {
        dbg("quirks=%d", usblp->quirks);
        dbg("used=%d", usblp->used);
        dbg("bidir=%d", usblp->bidir);
+       dbg("sleeping=%d", usblp->sleeping);
        dbg("device_id_string=\"%s\"",
                usblp->device_id_string ?
                        usblp->device_id_string + 2 :
@@ -338,6 +340,20 @@ static int usblp_check_status(struct usblp *usblp, int err)
        return newerr;
 }
 
+static int handle_bidir (struct usblp *usblp)
+{
+       if (usblp->bidir && usblp->used && !usblp->sleeping) {
+               usblp->readcount = 0;
+               usblp->readurb->dev = usblp->dev;
+               if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
+                       usblp->used = 0;
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * File op functions.
  */
@@ -390,14 +406,9 @@ static int usblp_open(struct inode *inode, struct file *file)
        usblp->writeurb->status = 0;
        usblp->readurb->status = 0;
 
-       if (usblp->bidir) {
-               usblp->readcount = 0;
-               usblp->readurb->dev = usblp->dev;
-               if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
-                       retval = -EIO;
-                       usblp->used = 0;
-                       file->private_data = NULL;
-               }
+       if (handle_bidir(usblp) < 0) {
+               file->private_data = NULL;
+               retval = -EIO;
        }
 out:
        mutex_unlock (&usblp_mutex);
@@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                goto done;
        }
 
+       if (usblp->sleeping) {
+               retval = -ENODEV;
+               goto done;
+       }
+
        dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
                _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
 
@@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                        return -ENODEV;
                }
 
+               if (usblp->sleeping) {
+                       up (&usblp->sem);
+                       return writecount ? writecount : -ENODEV;
+               }
+
                if (usblp->writeurb->status != 0) {
                        if (usblp->quirks & USBLP_QUIRK_BIDIR) {
                                if (!usblp->wcomplete)
@@ -749,6 +770,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
                goto done;
        }
 
+       if (usblp->sleeping) {
+               count = -ENODEV;
+               goto done;
+       }
+
        if (usblp->readurb->status) {
                err("usblp%d: error %d reading from printer",
                        usblp->minor, usblp->readurb->status);
@@ -1167,6 +1193,41 @@ static void usblp_disconnect(struct usb_interface *intf)
        mutex_unlock (&usblp_mutex);
 }
 
+static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
+{
+       struct usblp *usblp = usb_get_intfdata (intf);
+
+       /* this races against normal access and open */
+       mutex_lock (&usblp_mutex);
+       down (&usblp->sem);
+       /* we take no more IO */
+       usblp->sleeping = 1;
+       /* we wait for anything printing */
+       wait_event (usblp->wait, usblp->wcomplete || !usblp->present);
+       usblp_unlink_urbs(usblp);
+       up (&usblp->sem);
+       mutex_unlock (&usblp_mutex);
+
+       return 0;
+}
+
+static int usblp_resume (struct usb_interface *intf)
+{
+       struct usblp *usblp = usb_get_intfdata (intf);
+       int r;
+
+       mutex_lock (&usblp_mutex);
+       down (&usblp->sem);
+
+       usblp->sleeping = 0;
+       r = handle_bidir (usblp);
+
+       up (&usblp->sem);
+       mutex_unlock (&usblp_mutex);
+
+       return r;
+}
+
 static struct usb_device_id usblp_ids [] = {
        { USB_DEVICE_INFO(7, 1, 1) },
        { USB_DEVICE_INFO(7, 1, 2) },
@@ -1183,6 +1244,8 @@ static struct usb_driver usblp_driver = {
        .name =         "usblp",
        .probe =        usblp_probe,
        .disconnect =   usblp_disconnect,
+       .suspend =      usblp_suspend,
+       .resume =       usblp_resume,
        .id_table =     usblp_ids,
 };
 
index 724822cac2b1091894e63053af410777f29a8049..fed92be63b5ebf2ff0f5247b23b7bd349f4dcd85 100644 (file)
@@ -1588,15 +1588,18 @@ const struct file_operations usbfs_device_file_operations = {
        .release =      usbdev_release,
 };
 
-static void usbdev_add(struct usb_device *dev)
+static int usbdev_add(struct usb_device *dev)
 {
        int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
 
        dev->class_dev = class_device_create(usb_device_class, NULL,
                                MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
                                "usbdev%d.%d", dev->bus->busnum, dev->devnum);
+       if (IS_ERR(dev->class_dev))
+               return PTR_ERR(dev->class_dev);
 
        dev->class_dev->class_data = dev;
+       return 0;
 }
 
 static void usbdev_remove(struct usb_device *dev)
@@ -1609,7 +1612,8 @@ static int usbdev_notify(struct notifier_block *self, unsigned long action,
 {
        switch (action) {
        case USB_DEVICE_ADD:
-               usbdev_add(dev);
+               if (usbdev_add(dev))
+                       return NOTIFY_BAD;
                break;
        case USB_DEVICE_REMOVE:
                usbdev_remove(dev);
index 3ebb90149e93ef7319ae529c22da546032172730..3b2d137912beb6dce921d925adccff2873bb6f86 100644 (file)
@@ -223,7 +223,7 @@ int usb_create_ep_files(struct device *parent,
        ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
        if (!ep_dev) {
                retval = -ENOMEM;
-               goto exit;
+               goto error_alloc;
        }
 
        /* fun calculation to determine the minor of this endpoint */
@@ -241,33 +241,31 @@ int usb_create_ep_files(struct device *parent,
 
        retval = device_register(&ep_dev->dev);
        if (retval)
-               goto error;
+               goto error_register;
        retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
        if (retval)
                goto error_group;
 
-       endpoint->ep_dev = ep_dev;
-
        /* create the symlink to the old-style "ep_XX" directory */
        sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
-       retval = sysfs_create_link(&parent->kobj,
-                                  &endpoint->ep_dev->dev.kobj, name);
+       retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name);
        if (retval)
                goto error_link;
-exit:
+       endpoint->ep_dev = ep_dev;
        return retval;
 
 error_link:
        sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
-
 error_group:
        device_unregister(&ep_dev->dev);
-       endpoint->ep_dev = NULL;
        destroy_endpoint_class();
        return retval;
-error:
+
+error_register:
        kfree(ep_dev);
+error_alloc:
        destroy_endpoint_class();
+exit:
        return retval;
 }
 
@@ -282,8 +280,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
                sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp);
                device_unregister(&endpoint->ep_dev->dev);
                endpoint->ep_dev = NULL;
+               destroy_endpoint_class();
        }
-       destroy_endpoint_class();
 }
-
-
index d954daa8e9e072688a33554ca9e8969b6c7cadf2..3acc896a5d4c4abc08e6df1149d575ec52438da5 100644 (file)
@@ -1774,8 +1774,8 @@ static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL);
 
 #else
 
-#define device_create_file(a,b)        do {} while (0)
-#define device_remove_file     device_create_file
+#define device_create_file(a,b)        (0)
+#define device_remove_file(a,b)        do { } while (0)
 
 #endif
 
@@ -2044,8 +2044,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                return retval;
        }
 
-       device_create_file (&dev->pdev->dev, &dev_attr_function);
-       device_create_file (&dev->pdev->dev, &dev_attr_queues);
+       retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
+       if (retval) goto err_unbind;
+       retval = device_create_file (&dev->pdev->dev, &dev_attr_queues);
+       if (retval) goto err_func;
 
        /* ... then enable host detection and ep0; and we're ready
         * for set_configuration as well as eventual disconnect.
@@ -2060,6 +2062,14 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
 
        /* pci writes may still be posted */
        return 0;
+
+err_func:
+       device_remove_file (&dev->pdev->dev, &dev_attr_function);
+err_unbind:
+       driver->unbind (&dev->gadget);
+       dev->gadget.dev.driver = NULL;
+       dev->driver = NULL;
+       return retval;
 }
 EXPORT_SYMBOL (usb_gadget_register_driver);
 
@@ -2974,8 +2984,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
                                : "disabled");
        the_controller = dev;
 
-       device_register (&dev->gadget.dev);
-       device_create_file (&pdev->dev, &dev_attr_registers);
+       retval = device_register (&dev->gadget.dev);
+       if (retval) goto done;
+       retval = device_create_file (&pdev->dev, &dev_attr_registers);
+       if (retval) goto done;
 
        return 0;
 
index 23b95b2bfe1572e7788a6422e4a09f3a60261d2e..34b7a31cd85b90900a45a8626c186084a16f234f 100644 (file)
@@ -754,7 +754,9 @@ show_registers (struct class_device *class_dev, char *buf)
        }
 
        if (ehci->reclaim) {
-               temp = scnprintf (next, size, "reclaim qh %p\n", ehci->reclaim);
+               temp = scnprintf (next, size, "reclaim qh %p%s\n",
+                               ehci->reclaim,
+                               ehci->reclaim_ready ? " ready" : "");
                size -= temp;
                next += temp;
        }
index aac6ec5dd7cf5f70f0281affdd2ed2c38faeed0e..9030994aba985b5d2fd23b8e967a290263e30d42 100644 (file)
@@ -111,7 +111,7 @@ static const char   hcd_name [] = "ehci_hcd";
 #define        EHCI_TUNE_MULT_TT       1
 #define        EHCI_TUNE_FLS           2       /* (small) 256 frame schedule */
 
-#define EHCI_IAA_MSECS         10              /* arbitrary */
+#define EHCI_IAA_JIFFIES       (HZ/100)        /* arbitrary; ~10 msec */
 #define EHCI_IO_JIFFIES                (HZ/10)         /* io watchdog > irq_thresh */
 #define EHCI_ASYNC_JIFFIES     (HZ/20)         /* async idle timeout */
 #define EHCI_SHRINK_JIFFIES    (HZ/200)        /* async qh unlink delay */
@@ -254,7 +254,6 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
 
 /*-------------------------------------------------------------------------*/
 
-static void end_unlink_async (struct ehci_hcd *ehci);
 static void ehci_work(struct ehci_hcd *ehci);
 
 #include "ehci-hub.c"
@@ -264,37 +263,25 @@ static void ehci_work(struct ehci_hcd *ehci);
 
 /*-------------------------------------------------------------------------*/
 
-static void ehci_iaa_watchdog (unsigned long param)
+static void ehci_watchdog (unsigned long param)
 {
        struct ehci_hcd         *ehci = (struct ehci_hcd *) param;
        unsigned long           flags;
-       u32                     status;
 
        spin_lock_irqsave (&ehci->lock, flags);
-       WARN_ON(!ehci->reclaim);
 
-       /* lost IAA irqs wedge things badly; seen first with a vt8235 */
+       /* lost IAA irqs wedge things badly; seen with a vt8235 */
        if (ehci->reclaim) {
-               status = readl (&ehci->regs->status);
+               u32             status = readl (&ehci->regs->status);
                if (status & STS_IAA) {
                        ehci_vdbg (ehci, "lost IAA\n");
                        COUNT (ehci->stats.lost_iaa);
                        writel (STS_IAA, &ehci->regs->status);
-                       end_unlink_async (ehci);
+                       ehci->reclaim_ready = 1;
                }
        }
 
-       spin_unlock_irqrestore (&ehci->lock, flags);
-}
-
-static void ehci_watchdog (unsigned long param)
-{
-       struct ehci_hcd         *ehci = (struct ehci_hcd *) param;
-       unsigned long           flags;
-
-       spin_lock_irqsave (&ehci->lock, flags);
-
-       /* stop async processing after it's idled a bit */
+       /* stop async processing after it's idled a bit */
        if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
                start_unlink_async (ehci, ehci->async);
 
@@ -345,6 +332,8 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
 static void ehci_work (struct ehci_hcd *ehci)
 {
        timer_action_done (ehci, TIMER_IO_WATCHDOG);
+       if (ehci->reclaim_ready)
+               end_unlink_async (ehci);
 
        /* another CPU may drop ehci->lock during a schedule scan while
         * it reports urb completions.  this flag guards against bogus
@@ -379,7 +368,6 @@ static void ehci_stop (struct usb_hcd *hcd)
 
        /* no more interrupts ... */
        del_timer_sync (&ehci->watchdog);
-       del_timer_sync (&ehci->iaa_watchdog);
 
        spin_lock_irq(&ehci->lock);
        if (HC_IS_RUNNING (hcd->state))
@@ -426,10 +414,6 @@ static int ehci_init(struct usb_hcd *hcd)
        ehci->watchdog.function = ehci_watchdog;
        ehci->watchdog.data = (unsigned long) ehci;
 
-       init_timer(&ehci->iaa_watchdog);
-       ehci->iaa_watchdog.function = ehci_iaa_watchdog;
-       ehci->iaa_watchdog.data = (unsigned long) ehci;
-
        /*
         * hw default: 1K periodic list heads, one per frame.
         * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -446,6 +430,7 @@ static int ehci_init(struct usb_hcd *hcd)
                ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
 
        ehci->reclaim = NULL;
+       ehci->reclaim_ready = 0;
        ehci->next_uframe = -1;
 
        /*
@@ -619,7 +604,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        /* complete the unlinking of some qh [4.15.2.3] */
        if (status & STS_IAA) {
                COUNT (ehci->stats.reclaim);
-               end_unlink_async (ehci);
+               ehci->reclaim_ready = 1;
                bh = 1;
        }
 
@@ -723,14 +708,10 @@ static int ehci_urb_enqueue (
 
 static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-       // BUG_ON(qh->qh_state != QH_STATE_LINKED);
-
-       /* failfast */
-       if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
-               end_unlink_async (ehci);
-
-       /* defer till later if busy */
-       else if (ehci->reclaim) {
+       /* if we need to use IAA and it's busy, defer */
+       if (qh->qh_state == QH_STATE_LINKED
+                       && ehci->reclaim
+                       && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
                struct ehci_qh          *last;
 
                for (last = ehci->reclaim;
@@ -740,8 +721,12 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                qh->qh_state = QH_STATE_UNLINK_WAIT;
                last->reclaim = qh;
 
-       /* start IAA cycle */
-       } else
+       /* bypass IAA if the hc can't care */
+       } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
+               end_unlink_async (ehci);
+
+       /* something else might have unlinked the qh by now */
+       if (qh->qh_state == QH_STATE_LINKED)
                start_unlink_async (ehci, qh);
 }
 
@@ -763,19 +748,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
                qh = (struct ehci_qh *) urb->hcpriv;
                if (!qh)
                        break;
-               switch (qh->qh_state) {
-               case QH_STATE_LINKED:
-               case QH_STATE_COMPLETING:
-                       unlink_async (ehci, qh);
-                       break;
-               case QH_STATE_UNLINK:
-               case QH_STATE_UNLINK_WAIT:
-                       /* already started */
-                       break;
-               case QH_STATE_IDLE:
-                       WARN_ON(1);
-                       break;
-               }
+               unlink_async (ehci, qh);
                break;
 
        case PIPE_INTERRUPT:
@@ -867,7 +840,6 @@ rescan:
                unlink_async (ehci, qh);
                /* FALL THROUGH */
        case QH_STATE_UNLINK:           /* wait for hw to finish? */
-       case QH_STATE_UNLINK_WAIT:
 idle_timeout:
                spin_unlock_irqrestore (&ehci->lock, flags);
                schedule_timeout_uninterruptible(1);
index 2012213c0a254c719738c9a7ddd0f2bd46f002fb..1b20722c102b5ad5c936252a6c5f1243fc443de9 100644 (file)
@@ -48,7 +48,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        }
        ehci->command = readl (&ehci->regs->command);
        if (ehci->reclaim)
-               end_unlink_async (ehci);
+               ehci->reclaim_ready = 1;
        ehci_work(ehci);
 
        /* suspend any active/unsuspended ports, maybe allow wakeup */
index 35e3fab6fc4e85e23a8119424409c15e6b3c3333..e51c1ed81ac463cdc677c1a84883ede4e6a2ec9c 100644 (file)
@@ -303,7 +303,7 @@ restart:
        /* emptying the schedule aborts any urbs */
        spin_lock_irq(&ehci->lock);
        if (ehci->reclaim)
-               end_unlink_async (ehci);
+               ehci->reclaim_ready = 1;
        ehci_work(ehci);
        spin_unlock_irq(&ehci->lock);
 
index 46327272f6148b7c044bec6c8d5c4f0737546310..62e46dc60e86d6cbb3a6b36d28052f375b4aecfb 100644 (file)
@@ -967,7 +967,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
        struct ehci_qh          *qh = ehci->reclaim;
        struct ehci_qh          *next;
 
-       iaa_watchdog_done (ehci);
+       timer_action_done (ehci, TIMER_IAA_WATCHDOG);
 
        // qh->hw_next = cpu_to_le32 (qh->qh_dma);
        qh->qh_state = QH_STATE_IDLE;
@@ -977,6 +977,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
        /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
        next = qh->reclaim;
        ehci->reclaim = next;
+       ehci->reclaim_ready = 0;
        qh->reclaim = NULL;
 
        qh_completions (ehci, qh);
@@ -1051,10 +1052,11 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                return;
        }
 
+       ehci->reclaim_ready = 0;
        cmd |= CMD_IAAD;
        writel (cmd, &ehci->regs->command);
        (void) readl (&ehci->regs->command);
-       iaa_watchdog_start (ehci);
+       timer_action (ehci, TIMER_IAA_WATCHDOG);
 }
 
 /*-------------------------------------------------------------------------*/
index 6aac39f50e0734d35e33f2fb3cfd5c6e2fcec627..bbc3082a73d752ae359b4c45fb1ae59cd0764699 100644 (file)
@@ -58,6 +58,7 @@ struct ehci_hcd {                     /* one per controller */
        /* async schedule support */
        struct ehci_qh          *async;
        struct ehci_qh          *reclaim;
+       unsigned                reclaim_ready : 1;
        unsigned                scanning : 1;
 
        /* periodic schedule support */
@@ -80,7 +81,6 @@ struct ehci_hcd {                     /* one per controller */
        struct dma_pool         *itd_pool;      /* itd per iso urb */
        struct dma_pool         *sitd_pool;     /* sitd per split iso urb */
 
-       struct timer_list       iaa_watchdog;
        struct timer_list       watchdog;
        unsigned long           actions;
        unsigned                stamp;
@@ -114,21 +114,9 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
 }
 
 
-static inline void
-iaa_watchdog_start (struct ehci_hcd *ehci)
-{
-       WARN_ON(timer_pending(&ehci->iaa_watchdog));
-       mod_timer (&ehci->iaa_watchdog,
-                       jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
-}
-
-static inline void iaa_watchdog_done (struct ehci_hcd *ehci)
-{
-       del_timer (&ehci->iaa_watchdog);
-}
-
 enum ehci_timer_action {
        TIMER_IO_WATCHDOG,
+       TIMER_IAA_WATCHDOG,
        TIMER_ASYNC_SHRINK,
        TIMER_ASYNC_OFF,
 };
@@ -146,6 +134,9 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
                unsigned long t;
 
                switch (action) {
+               case TIMER_IAA_WATCHDOG:
+                       t = EHCI_IAA_JIFFIES;
+                       break;
                case TIMER_IO_WATCHDOG:
                        t = EHCI_IO_JIFFIES;
                        break;
@@ -162,7 +153,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
                // async queue SHRINK often precedes IAA.  while it's ready
                // to go OFF neither can matter, and afterwards the IO
                // watchdog stops unless there's still periodic traffic.
-               if (time_before_eq(t, ehci->watchdog.expires)
+               if (action != TIMER_IAA_WATCHDOG
+                               && t > ehci->watchdog.expires
                                && timer_pending (&ehci->watchdog))
                        return;
                mod_timer (&ehci->watchdog, t);
index 82cb22f002e775a3d9078ed8f475d99cc2b667f3..2dbb77414905209969e86724c5a15f80791c061c 100644 (file)
@@ -262,6 +262,7 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
         */
        .start = ohci_pnx4008_start,
        .stop = ohci_stop,
+       .shutdown = ohci_shutdown,
 
        /*
         * managing i/o requests and associated device resources
@@ -280,7 +281,11 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
         */
        .hub_status_data = ohci_hub_status_data,
        .hub_control = ohci_hub_control,
-
+       .hub_irq_enable = ohci_rhsc_enable,
+#ifdef CONFIG_PM
+       .bus_suspend = ohci_bus_suspend,
+       .bus_resume = ohci_bus_resume,
+#endif
        .start_port_reset = ohci_start_port_reset,
 };
 
@@ -410,8 +415,6 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
                goto out4;
        }
 
-       hcd->self.hcpriv = (void *)hcd;
-
        pnx4008_start_hc();
        platform_set_drvdata(pdev, hcd);
        ohci = hcd_to_ohci(hcd);
index 45ee6920a850b6369ec7ecd883d2278ecc815830..226bf3de8edd5ce092c551f0a90daa96ba2fc9e4 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/usb.h>
 #include <linux/bitops.h>
+#include <linux/dmi.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -196,12 +197,42 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
        return 0;
 }
 
+static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
+{
+       static struct dmi_system_id broken_wakeup_table[] = {
+               {
+                       .ident = "Asus A7V8X",
+                       .matches = {
+                               DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK"),
+                               DMI_MATCH(DMI_BOARD_NAME, "A7V8X"),
+                               DMI_MATCH(DMI_BOARD_VERSION, "REV 1.xx"),
+                       }
+               },
+               { }
+       };
+       int port;
+
+       /* One of Asus's motherboards has a bug which causes it to
+        * wake up immediately from suspend-to-RAM if any of the ports
+        * are connected.  In such cases we will not set EGSM.
+        */
+       if (dmi_check_system(broken_wakeup_table)) {
+               for (port = 0; port < uhci->rh_numports; ++port) {
+                       if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+                                       USBPORTSC_CCS)
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
 static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
 __releases(uhci->lock)
 __acquires(uhci->lock)
 {
        int auto_stop;
-       int int_enable;
+       int int_enable, egsm_enable;
 
        auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
        dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
@@ -217,15 +248,18 @@ __acquires(uhci->lock)
        }
 
        /* Enable resume-detect interrupts if they work.
-        * Then enter Global Suspend mode, still configured.
+        * Then enter Global Suspend mode if _it_ works, still configured.
         */
+       egsm_enable = USBCMD_EGSM;
        uhci->working_RD = 1;
        int_enable = USBINTR_RESUME;
-       if (resume_detect_interrupts_are_broken(uhci)) {
+       if (remote_wakeup_is_broken(uhci))
+               egsm_enable = 0;
+       if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable)
                uhci->working_RD = int_enable = 0;
-       }
+
        outw(int_enable, uhci->io_addr + USBINTR);
-       outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
+       outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
        mb();
        udelay(5);
 
index 21cd22640080fbce6d032354409f59dc61de32a3..20db36448ab377d6c763ccbd472037c440a5eb92 100644 (file)
@@ -348,13 +348,3 @@ config USB_APPLETOUCH
 
          To compile this driver as a module, choose M here: the
          module will be called appletouch.
-
-config USB_TRANCEVIBRATOR
-       tristate "PlayStation 2 Trance Vibrator driver support"
-       depends on USB
-       help
-         Say Y here if you want to connect a PlayStation 2 Trance Vibrator
-         device to your computer's USB port.
-
-         To compile this driver as a module, choose M here: the
-         module will be called trancevibrator.
index 295f459d1079ffa4c3afe69bb38d61474f503162..d946d5213b30d0481035406caf1ada2101f178f7 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Multipart objects.
-wacom-objs     := wacom_sys.o wacom_wac.o
+wacom-objs     := wacom_wac.o wacom_sys.o
 usbhid-objs    := hid-core.o
 
 # Optional parts of multipart objects.
@@ -48,7 +48,6 @@ obj-$(CONFIG_USB_ACECAD)      += acecad.o
 obj-$(CONFIG_USB_YEALINK)      += yealink.o
 obj-$(CONFIG_USB_XPAD)         += xpad.o
 obj-$(CONFIG_USB_APPLETOUCH)   += appletouch.o
-obj-$(CONFIG_USB_TRANCEVIBRATOR)       += trancevibrator.o
 
 ifeq ($(CONFIG_USB_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
index a6738a83ff5b109ecb1886961ddb0152e040d8f4..feabda73a6f9cd2ea67dacd672ad8f8ea9f0e3af 100644 (file)
@@ -750,21 +750,31 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n)
 }
 
 /*
- * Extract/implement a data field from/to a report.
+ * Extract/implement a data field from/to a little endian report (bit array).
  */
 
 static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
 {
-       report += (offset >> 5) << 2; offset &= 31;
-       return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1);
+       u32 x;
+
+       report += offset >> 3;  /* adjust byte index */
+       offset &= 8 - 1;
+       x = get_unaligned((u32 *) report);
+       x = le32_to_cpu(x);
+       x = (x >> offset) & ((1 << n) - 1);
+       return x;
 }
 
 static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
 {
-       report += (offset >> 5) << 2; offset &= 31;
-       put_unaligned((get_unaligned((__le64*)report)
-               & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset)))
-               | cpu_to_le64((__u64)value << offset), (__le64*)report);
+       u32 x;
+
+       report += offset >> 3;
+       offset &= 8 - 1;
+       x = get_unaligned((u32 *)report);
+       x &= cpu_to_le32(~((((__u32) 1 << n) - 1) << offset));
+       x |= cpu_to_le32(value << offset);
+       put_unaligned(x,(u32 *)report);
 }
 
 /*
diff --git a/drivers/usb/input/trancevibrator.c b/drivers/usb/input/trancevibrator.c
deleted file mode 100644 (file)
index 33cd91d..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * PlayStation 2 Trance Vibrator driver
- *
- * Copyright (C) 2006 Sam Hocevar <sam@zoy.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Standard include files */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-
-/* Version Information */
-#define DRIVER_VERSION "v1.1"
-#define DRIVER_AUTHOR "Sam Hocevar, sam@zoy.org"
-#define DRIVER_DESC "PlayStation 2 Trance Vibrator driver"
-
-#define TRANCEVIBRATOR_VENDOR_ID       0x0b49  /* ASCII Corporation */
-#define TRANCEVIBRATOR_PRODUCT_ID      0x064f  /* Trance Vibrator */
-
-static struct usb_device_id id_table [] = {
-       { USB_DEVICE(TRANCEVIBRATOR_VENDOR_ID, TRANCEVIBRATOR_PRODUCT_ID) },
-       { },
-};
-MODULE_DEVICE_TABLE (usb, id_table);
-
-/* Driver-local specific stuff */
-struct trancevibrator {
-       struct usb_device *udev;
-       unsigned int speed;
-};
-
-static ssize_t show_speed(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       struct usb_interface *intf = to_usb_interface(dev);
-       struct trancevibrator *tv = usb_get_intfdata(intf);
-
-       return sprintf(buf, "%d\n", tv->speed);
-}
-
-static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
-                        const char *buf, size_t count)
-{
-       struct usb_interface *intf = to_usb_interface(dev);
-       struct trancevibrator *tv = usb_get_intfdata(intf);
-       int temp, retval;
-
-       temp = simple_strtoul(buf, NULL, 10);
-       if (temp > 255)
-               temp = 255;
-       else if (temp < 0)
-               temp = 0;
-       tv->speed = temp;
-
-       dev_dbg(&tv->udev->dev, "speed = %d\n", tv->speed);
-
-       /* Set speed */
-       retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0),
-                                0x01, /* vendor request: set speed */
-                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
-                                tv->speed, /* speed value */
-                                0, NULL, 0, USB_CTRL_GET_TIMEOUT);
-       if (retval) {
-               dev_dbg(&tv->udev->dev, "retval = %d\n", retval);
-               return retval;
-       }
-       return count;
-}
-
-static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed);
-
-static int tv_probe(struct usb_interface *interface,
-                   const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(interface);
-       struct trancevibrator *dev;
-       int retval;
-
-       dev = kzalloc(sizeof(struct trancevibrator), GFP_KERNEL);
-       if (dev == NULL) {
-               dev_err(&interface->dev, "Out of memory\n");
-               retval = -ENOMEM;
-               goto error;
-       }
-
-       dev->udev = usb_get_dev(udev);
-       usb_set_intfdata(interface, dev);
-       retval = device_create_file(&interface->dev, &dev_attr_speed);
-       if (retval)
-               goto error_create_file;
-
-       return 0;
-
-error_create_file:
-       usb_put_dev(udev);
-       usb_set_intfdata(interface, NULL);
-error:
-       kfree(dev);
-       return retval;
-}
-
-static void tv_disconnect(struct usb_interface *interface)
-{
-       struct trancevibrator *dev;
-
-       dev = usb_get_intfdata (interface);
-       usb_set_intfdata(interface, NULL);
-       device_remove_file(&interface->dev, &dev_attr_speed);
-       usb_put_dev(dev->udev);
-       kfree(dev);
-}
-
-/* USB subsystem object */
-static struct usb_driver tv_driver = {
-       .name =         "trancevibrator",
-       .probe =        tv_probe,
-       .disconnect =   tv_disconnect,
-       .id_table =     id_table,
-};
-
-static int __init tv_init(void)
-{
-       int retval = usb_register(&tv_driver);
-       if (retval) {
-               err("usb_register failed. Error number %d", retval);
-               return retval;
-       }
-
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-       return 0;
-}
-
-static void __exit tv_exit(void)
-{
-       usb_deregister(&tv_driver);
-}
-
-module_init (tv_init);
-module_exit (tv_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
index f26c1cd1129f47833fc3cffcc8aed7a07d2c2c2b..2902742895ad875f71ea55c4aaea5a30af508a01 100644 (file)
@@ -256,10 +256,10 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr
 {
        *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
        *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
-       *press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F);
+       *press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
        *touch = ~pkt[7] & 0x20;
 
-       return 1;
+       return *touch;
 }
 #endif
 
index 7b3840e378a8aa802f6853be64a6511cf0d29065..1cf08f02c50e8a8871aff028f2ac01983627c2f1 100644 (file)
@@ -63,6 +63,7 @@
  *      v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
  *                - where wacom_sys.c deals with system specific code,
  *                - and wacom_wac.c deals with Wacom specific code
+ *                - Support Intuos3 4x6
  */
 
 /*
@@ -118,6 +119,7 @@ extern void wacom_input_sync(void *wcombo);
 extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
index d233c37bd533b76743c33d9ed99036b8fbccc3ee..3498b893b53b62b6a792ddebcceafcb0ab5e890d 100644 (file)
@@ -110,7 +110,7 @@ __u16 wacom_be16_to_cpu(unsigned char *data)
 __u16 wacom_le16_to_cpu(unsigned char *data)
 {
        __u16 value;
-       value = be16_to_cpu(*(__be16 *) data);
+       value = le16_to_cpu(*(__le16 *) data);
        return value;
 }
 
@@ -143,7 +143,7 @@ void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
        input_dev->evbit[0] |= BIT(EV_MSC);
        input_dev->mscbit[0] |= BIT(MSC_SERIAL);
        input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
-       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
+       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4);
 }
 
 void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
@@ -155,11 +155,16 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
        input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
 }
 
-void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
        input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
-       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
+       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3);
        input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0);
+}
+
+void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
        input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0);
 }
 
@@ -218,8 +223,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
 
        wacom_wac->features = get_wacom_feature(id);
-       if (wacom_wac->features->pktlen > 10)
-               BUG();
+       BUG_ON(wacom_wac->features->pktlen > 10);
 
        input_dev->name = wacom_wac->features->name;
        wacom->wacom_wac = wacom_wac;
@@ -244,7 +248,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        usb_fill_int_urb(wacom->irq, dev,
                         usb_rcvintpipe(dev, endpoint->bEndpointAddress),
                         wacom_wac->data, wacom_wac->features->pktlen,
-                        wacom_wac->features->irq, wacom, endpoint->bInterval);
+                        wacom_sys_irq, wacom, endpoint->bInterval);
        wacom->irq->transfer_dma = wacom->data_dma;
        wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -278,8 +282,8 @@ static void wacom_disconnect(struct usb_interface *intf)
                input_unregister_device(wacom->dev);
                usb_free_urb(wacom->irq);
                usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma);
-               kfree(wacom);
                kfree(wacom->wacom_wac);
+               kfree(wacom);
        }
 }
 
index aa31d22d4f0504c94f72d210b08f5984f4f265f6..92726fe89379e7631f7c3bf382063ed7859c5e26 100644 (file)
@@ -191,9 +191,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
                                wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
                                wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
                                if (wacom->features->type == WACOM_G4)
-                                       wacom_report_abs(wcombo, ABS_DISTANCE, data[6]);
+                                       wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
                                else
-                                       wacom_report_abs(wcombo, ABS_DISTANCE, data[7]);
+                                       wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
                                break;
                }
        }
@@ -303,8 +303,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
                                wacom->tool[idx] = BTN_TOOL_PEN;
                }
                /* only large I3 support Lens Cursor */
-               if(!((wacom->tool[idx] == BTN_TOOL_LENS) &&
-                               (wacom->features->type == INTUOS3))) {
+               if(!((wacom->tool[idx] == BTN_TOOL_LENS)
+                                && ((wacom->features->type == INTUOS3)
+                                || (wacom->features->type == INTUOS3S)))) {
                        wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
                        wacom_report_key(wcombo, wacom->tool[idx], 1);
                        wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
@@ -315,10 +316,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
 
        /* Exit report */
        if ((data[1] & 0xfe) == 0x80) {
-               wacom_report_key(wcombo, wacom->tool[idx], 0);
-               wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
-               wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-               return 2;
+               if(!((wacom->tool[idx] == BTN_TOOL_LENS)
+                                && ((wacom->features->type == INTUOS3)
+                                || (wacom->features->type == INTUOS3S)))) {
+                       wacom_report_key(wcombo, wacom->tool[idx], 0);
+                       wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+                       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+                       return 2;
+               }
        }
        return 0;
 }
@@ -382,7 +387,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
                wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
 
-               if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2])
+               if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) |
+                       data[2] | (data[3] & 0x1f) | data[4])
                        wacom_report_key(wcombo, wacom->tool[1], 1);
                else
                        wacom_report_key(wcombo, wacom->tool[1], 0);
@@ -432,7 +438,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                                        ((t - 1) / 2) : -t / 2);
                        }
 
-               } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) {
+               } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) {
                        /* 4D mouse packet */
                        wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
                        wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
@@ -452,12 +458,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
                                                 - ((data[8] & 0x02) >> 1));
 
                        /* I3 2D mouse side buttons */
-                       if (wacom->features->type == INTUOS3) {
+                       if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
                                wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x40);
                                wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x20);
                        }
 
-               } else if (wacom->features->type < INTUOS3) {
+               } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) {
                        /* Lens cursor packets */
                        wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
                        wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
@@ -490,6 +496,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
                        return (wacom_ptu_irq(wacom_wac, wcombo));
                        break;
                case INTUOS:
+               case INTUOS3S:
                case INTUOS3:
                case INTUOS3L:
                case CINTIQ:
@@ -515,6 +522,8 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
                case CINTIQ:
                        input_dev_i3(input_dev, wacom_wac);
                        /* fall through */
+               case INTUOS3S:
+                       input_dev_i3s(input_dev, wacom_wac);
                case INTUOS:
                        input_dev_i(input_dev, wacom_wac);
                        break;
@@ -530,49 +539,50 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
 }
 
 static struct wacom_features wacom_features[] = {
-       { "Wacom Penpartner",    7,   5040,  3780,  255, 32, PENPARTNER,        wacom_sys_irq },
-        { "Wacom Graphire",      8,  10206,  7422,  511, 32, GRAPHIRE, wacom_sys_irq },
-       { "Wacom Graphire2 4x5", 8,  10206,  7422,  511, 32, GRAPHIRE,  wacom_sys_irq },
-       { "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 32, GRAPHIRE,  wacom_sys_irq },
-       { "Wacom Graphire3",     8,  10208,  7424,  511, 32, GRAPHIRE,  wacom_sys_irq },
-       { "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 32, GRAPHIRE,  wacom_sys_irq },
-       { "Wacom Graphire4 4x5", 8,  10208,  7424,  511, 32, WACOM_G4,  wacom_sys_irq },
-       { "Wacom Graphire4 6x8", 8,  16704, 12064,  511, 32, WACOM_G4,  wacom_sys_irq },
-       { "Wacom Volito",        8,   5104,  3712,  511, 32, GRAPHIRE,  wacom_sys_irq },
-       { "Wacom PenStation2",   8,   3250,  2320,  255, 32, GRAPHIRE,  wacom_sys_irq },
-       { "Wacom Volito2 4x5",   8,   5104,  3712,  511, 32, GRAPHIRE,  wacom_sys_irq },
-       { "Wacom Volito2 2x3",   8,   3248,  2320,  511, 32, GRAPHIRE,  wacom_sys_irq },
-       { "Wacom PenPartner2",   8,   3250,  2320,  255, 32, GRAPHIRE,  wacom_sys_irq },
-       { "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 15, INTUOS,    wacom_sys_irq},
-       { "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 15, INTUOS,    wacom_sys_irq },
-       { "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 15, INTUOS,    wacom_sys_irq },
-       { "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 15, INTUOS,    wacom_sys_irq },
-       { "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 15, INTUOS,    wacom_sys_irq},
-       { "Wacom PL400",         8,   5408,  4056,  255, 32, PL,        wacom_sys_irq },
-       { "Wacom PL500",         8,   6144,  4608,  255, 32, PL,        wacom_sys_irq },
-       { "Wacom PL600",         8,   6126,  4604,  255, 32, PL,        wacom_sys_irq },
-       { "Wacom PL600SX",       8,   6260,  5016,  255, 32, PL,        wacom_sys_irq },
-       { "Wacom PL550",         8,   6144,  4608,  511, 32, PL,        wacom_sys_irq },
-       { "Wacom PL800",         8,   7220,  5780,  511, 32, PL,        wacom_sys_irq },
-       { "Wacom PL700",         8,   6758,  5406,  511, 32, PL,        wacom_sys_irq },
-       { "Wacom PL510",         8,   6282,  4762,  511, 32, PL,        wacom_sys_irq },
-       { "Wacom DTU710",        8,  34080, 27660,  511, 32, PL,        wacom_sys_irq },
-       { "Wacom DTF521",        8,   6282,  4762,  511, 32, PL,        wacom_sys_irq },
-       { "Wacom DTF720",        8,   6858,  5506,  511, 32, PL,        wacom_sys_irq },
-       { "Wacom Cintiq Partner",8,  20480, 15360,  511, 32, PTU,       wacom_sys_irq },
-       { "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 15, INTUOS,    wacom_sys_irq },
-       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, INTUOS,    wacom_sys_irq },
-       { "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 15, INTUOS,    wacom_sys_irq },
-       { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS,    wacom_sys_irq },
-       { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS,    wacom_sys_irq },
-       { "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 15, INTUOS3,   wacom_sys_irq },
-       { "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 15, INTUOS3,   wacom_sys_irq },
-       { "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 15, INTUOS3,   wacom_sys_irq },
-       { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS3L,  wacom_sys_irq },
-       { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS3L,  wacom_sys_irq },
-       { "Wacom Intuos3 6x11",  10, 54204, 31750, 1023, 15, INTUOS3,   wacom_sys_irq },
-       { "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 15, CINTIQ,    wacom_sys_irq },
-       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 15, INTUOS,    wacom_sys_irq },
+       { "Wacom Penpartner",    7,   5040,  3780,  255,  0, PENPARTNER },
+        { "Wacom Graphire",      8,  10206,  7422,  511, 63, GRAPHIRE },
+       { "Wacom Graphire2 4x5", 8,  10206,  7422,  511, 63, GRAPHIRE },
+       { "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 63, GRAPHIRE },
+       { "Wacom Graphire3",     8,  10208,  7424,  511, 63, GRAPHIRE },
+       { "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 63, GRAPHIRE },
+       { "Wacom Graphire4 4x5", 8,  10208,  7424,  511, 63, WACOM_G4 },
+       { "Wacom Graphire4 6x8", 8,  16704, 12064,  511, 63, WACOM_G4 },
+       { "Wacom Volito",        8,   5104,  3712,  511,  0, GRAPHIRE },
+       { "Wacom PenStation2",   8,   3250,  2320,  255,  0, GRAPHIRE },
+       { "Wacom Volito2 4x5",   8,   5104,  3712,  511,  0, GRAPHIRE },
+       { "Wacom Volito2 2x3",   8,   3248,  2320,  511,  0, GRAPHIRE },
+       { "Wacom PenPartner2",   8,   3250,  2320,  255,  0, GRAPHIRE },
+       { "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 63, INTUOS },
+       { "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 63, INTUOS },
+       { "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 63, INTUOS },
+       { "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 63, INTUOS },
+       { "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 63, INTUOS },
+       { "Wacom PL400",         8,   5408,  4056,  255,  0, PL },
+       { "Wacom PL500",         8,   6144,  4608,  255,  0, PL },
+       { "Wacom PL600",         8,   6126,  4604,  255,  0, PL },
+       { "Wacom PL600SX",       8,   6260,  5016,  255,  0, PL },
+       { "Wacom PL550",         8,   6144,  4608,  511,  0, PL },
+       { "Wacom PL800",         8,   7220,  5780,  511,  0, PL },
+       { "Wacom PL700",         8,   6758,  5406,  511,  0, PL },
+       { "Wacom PL510",         8,   6282,  4762,  511,  0, PL },
+       { "Wacom DTU710",        8,  34080, 27660,  511,  0, PL },
+       { "Wacom DTF521",        8,   6282,  4762,  511,  0, PL },
+       { "Wacom DTF720",        8,   6858,  5506,  511,  0, PL },
+       { "Wacom Cintiq Partner",8,  20480, 15360,  511,  0, PTU },
+       { "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 63, INTUOS },
+       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 63, INTUOS },
+       { "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 63, INTUOS },
+       { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
+       { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
+       { "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 63, INTUOS3S },
+       { "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 63, INTUOS3 },
+       { "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 63, INTUOS3 },
+       { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L },
+       { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L },
+       { "Wacom Intuos3 6x11",  10, 54204, 31750, 1023, 63, INTUOS3 },
+       { "Wacom Intuos3 4x6",   10, 31496, 19685, 1023, 15, INTUOS3S },
+       { "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 63, CINTIQ },
+       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 63, INTUOS },
        { }
 };
 
@@ -618,6 +628,7 @@ static struct usb_device_id wacom_ids[] = {
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
        { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
        { }
index ceae7bf59d9f8b13a19c26403a5cf3661aa6e1cd..a1d9ce007970b12084c78c81e51cd0551541d3d1 100644 (file)
@@ -20,6 +20,7 @@ enum {
        PTU,
        PL,
        INTUOS,
+       INTUOS3S,
        INTUOS3,
        INTUOS3L,
        CINTIQ,
@@ -34,7 +35,6 @@ struct wacom_features {
        int pressure_max;
        int distance_max;
        int type;
-       usb_complete_t irq;
 };
 
 struct wacom_wac {
index cebb6c463bfbadcdf204c5d8453c10a9d4a1acaf..6a12a943b938a189424b12526cb1ed28fa03ebd4 100644 (file)
@@ -1,8 +1,9 @@
 /*
- * X-Box gamepad - v0.0.5
+ * X-Box gamepad - v0.0.6
  *
  * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
- *
+ *               2005 Dominic Cerquetti <binary1230@yahoo.com>
+ *               2006 Adam Buchbinder <adam.buchbinder@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  *  - Greg Kroah-Hartman - usb-skeleton driver
  *
  * TODO:
- *  - fine tune axes
+ *  - fine tune axes (especially trigger axes)
  *  - fix "analog" buttons (reported as digital now)
  *  - get rumble working
+ *  - need USB IDs for other dance pads
  *
  * History:
  *
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/stat.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/smp_lock.h>
 #include <linux/usb/input.h>
 
-#define DRIVER_VERSION "v0.0.5"
+#define DRIVER_VERSION "v0.0.6"
 #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
 #define DRIVER_DESC "X-Box pad driver"
 
 #define XPAD_PKT_LEN 32
 
+/* xbox d-pads should map to buttons, as is required for DDR pads
+   but we map them to axes when possible to simplify things */
+#define MAP_DPAD_TO_BUTTONS    0
+#define MAP_DPAD_TO_AXES       1
+#define MAP_DPAD_UNKNOWN       -1
+
+static int dpad_to_buttons;
+module_param(dpad_to_buttons, bool, S_IRUGO);
+MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
+
 static const struct xpad_device {
        u16 idVendor;
        u16 idProduct;
        char *name;
+       u8 dpad_mapping;
 } xpad_device[] = {
-       { 0x045e, 0x0202, "Microsoft X-Box pad (US)" },
-       { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" },
-       { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" },
-       { 0x0000, 0x0000, "X-Box pad" }
+       { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES },
+       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES },
+       { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES },
+       { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES },
+       { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS },
+       { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN }
 };
 
 static const signed short xpad_btn[] = {
@@ -84,11 +101,23 @@ static const signed short xpad_btn[] = {
        -1                                              /* terminating entry */
 };
 
+/* only used if MAP_DPAD_TO_BUTTONS */
+static const signed short xpad_btn_pad[] = {
+       BTN_LEFT, BTN_RIGHT,            /* d-pad left, right */
+       BTN_0, BTN_1,                   /* d-pad up, down (XXX names??) */
+       -1                              /* terminating entry */
+};
+
 static const signed short xpad_abs[] = {
        ABS_X, ABS_Y,           /* left stick */
        ABS_RX, ABS_RY,         /* right stick */
        ABS_Z, ABS_RZ,          /* triggers left/right */
-       ABS_HAT0X, ABS_HAT0Y,   /* digital pad */
+       -1                      /* terminating entry */
+};
+
+/* only used if MAP_DPAD_TO_AXES */
+static const signed short xpad_abs_pad[] = {
+       ABS_HAT0X, ABS_HAT0Y,   /* d-pad axes */
        -1                      /* terminating entry */
 };
 
@@ -100,14 +129,16 @@ static struct usb_device_id xpad_table [] = {
 MODULE_DEVICE_TABLE (usb, xpad_table);
 
 struct usb_xpad {
-       struct input_dev *dev;                  /* input device interface */
-       struct usb_device *udev;                /* usb device */
+       struct input_dev *dev;          /* input device interface */
+       struct usb_device *udev;        /* usb device */
 
-       struct urb *irq_in;                     /* urb for interrupt in report */
-       unsigned char *idata;                   /* input data */
+       struct urb *irq_in;             /* urb for interrupt in report */
+       unsigned char *idata;           /* input data */
        dma_addr_t idata_dma;
 
-       char phys[65];                          /* physical device path */
+       char phys[65];                  /* physical device path */
+
+       int dpad_mapping;               /* map d-pad to buttons or to axes */
 };
 
 /*
@@ -137,14 +168,21 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
        input_report_abs(dev, ABS_RZ, data[11]);
 
        /* digital pad */
-       input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
-       input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
+       if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
+               input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
+               input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
+       } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
+               input_report_key(dev, BTN_LEFT,  data[2] & 0x04);
+               input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
+               input_report_key(dev, BTN_0,     data[2] & 0x01); // up
+               input_report_key(dev, BTN_1,     data[2] & 0x02); // down
+       }
 
        /* start/back buttons and stick press left/right */
-       input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4);
-       input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5);
-       input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6);
-       input_report_key(dev, BTN_THUMBR, data[2] >> 7);
+       input_report_key(dev, BTN_START,  data[2] & 0x10);
+       input_report_key(dev, BTN_BACK,   data[2] & 0x20);
+       input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
+       input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
 
        /* "analog" buttons A, B, X, Y */
        input_report_key(dev, BTN_A, data[4]);
@@ -206,6 +244,28 @@ static void xpad_close (struct input_dev *dev)
        usb_kill_urb(xpad->irq_in);
 }
 
+static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
+{
+       set_bit(abs, input_dev->absbit);
+
+       switch (abs) {
+       case ABS_X:
+       case ABS_Y:
+       case ABS_RX:
+       case ABS_RY:    /* the two sticks */
+               input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
+               break;
+       case ABS_Z:
+       case ABS_RZ:    /* the triggers */
+               input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
+               break;
+       case ABS_HAT0X:
+       case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */
+               input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
+               break;
+       }
+}
+
 static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct usb_device *udev = interface_to_usbdev (intf);
@@ -235,6 +295,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                goto fail2;
 
        xpad->udev = udev;
+       xpad->dpad_mapping = xpad_device[i].dpad_mapping;
+       if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
+               xpad->dpad_mapping = dpad_to_buttons;
        xpad->dev = input_dev;
        usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
        strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
@@ -249,32 +312,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 
        input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
+       /* set up buttons */
        for (i = 0; xpad_btn[i] >= 0; i++)
                set_bit(xpad_btn[i], input_dev->keybit);
+       if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
+               for (i = 0; xpad_btn_pad[i] >= 0; i++)
+                       set_bit(xpad_btn_pad[i], input_dev->keybit);
 
-       for (i = 0; xpad_abs[i] >= 0; i++) {
-
-               signed short t = xpad_abs[i];
-
-               set_bit(t, input_dev->absbit);
-
-               switch (t) {
-                       case ABS_X:
-                       case ABS_Y:
-                       case ABS_RX:
-                       case ABS_RY:    /* the two sticks */
-                               input_set_abs_params(input_dev, t, -32768, 32767, 16, 128);
-                               break;
-                       case ABS_Z:
-                       case ABS_RZ:    /* the triggers */
-                               input_set_abs_params(input_dev, t, 0, 255, 0, 0);
-                               break;
-                       case ABS_HAT0X:
-                       case ABS_HAT0Y: /* the d-pad */
-                               input_set_abs_params(input_dev, t, -1, 1, 0, 0);
-                               break;
-               }
-       }
+       /* set up axes */
+       for (i = 0; xpad_abs[i] >= 0; i++)
+               xpad_set_up_abs(input_dev, xpad_abs[i]);
+       if (xpad->dpad_mapping == MAP_DPAD_TO_AXES)
+               for (i = 0; xpad_abs_pad[i] >= 0; i++)
+                   xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
 
        ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
        usb_fill_int_urb(xpad->irq_in, udev,
@@ -305,7 +355,8 @@ static void xpad_disconnect(struct usb_interface *intf)
                usb_kill_urb(xpad->irq_in);
                input_unregister_device(xpad->dev);
                usb_free_urb(xpad->irq_in);
-               usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
+               usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN,
+                               xpad->idata, xpad->idata_dma);
                kfree(xpad);
        }
 }
index c29658f69e2a8c0db81dc26a9d1fe9addb1bb96a..a74bf8617e7f3f11cbb67397e0bd6cef9b160483 100644 (file)
@@ -223,6 +223,16 @@ config USB_LD
          To compile this driver as a module, choose M here: the
          module will be called ldusb.
 
+config USB_TRANCEVIBRATOR
+       tristate "PlayStation 2 Trance Vibrator driver support"
+       depends on USB
+       help
+         Say Y here if you want to connect a PlayStation 2 Trance Vibrator
+         device to your computer's USB port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called trancevibrator.
+
 config USB_TEST
        tristate "USB testing driver (DEVELOPMENT)"
        depends on USB && USB_DEVICEFS && EXPERIMENTAL
index 2be70fa259bfe16cc45ebbdcae5db57dd33dcd9d..11dc59540cda11eaf501427ae43242bfe4c5e742 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_USB_PHIDGETMOTORCONTROL) += phidgetmotorcontrol.o
 obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o
 obj-$(CONFIG_USB_RIO500)       += rio500.o
 obj-$(CONFIG_USB_TEST)         += usbtest.o
+obj-$(CONFIG_USB_TRANCEVIBRATOR)       += trancevibrator.o
 obj-$(CONFIG_USB_USS720)       += uss720.o
 
 obj-$(CONFIG_USB_SISUSBVGA)    += sisusbvga/
index aecd633fe9f6966f20a9879f8b455675ffbc7d27..af2934e016a7e76313816ba480e81a060de5a4b4 100644 (file)
@@ -370,7 +370,8 @@ static int adu_release(struct inode *inode, struct file *file)
        retval = adu_release_internal(dev);
 
 exit:
-       up(&dev->sem);
+       if (dev)
+               up(&dev->sem);
        dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
        return retval;
 }
index 0eb26a26115ba896677e8686763e080d2bd2cfd0..9b591b8b9369b2e67708ffb79cd01cd997451838 100644 (file)
@@ -513,8 +513,6 @@ static void ftdi_elan_respond_work(void *data)
                         ftdi->disconnected += 1;
                 } else if (retval == -ENODEV) {
                         ftdi->disconnected += 1;
-                } else if (retval == -ENODEV) {
-                        ftdi->disconnected += 1;
                 } else if (retval == -EILSEQ) {
                         ftdi->disconnected += 1;
                 } else {
@@ -1186,11 +1184,8 @@ static ssize_t ftdi_elan_write(struct file *file,
         int retval = 0;
         struct urb *urb;
         char *buf;
-        char data[30 *3 + 4];
-        char *d = data;
-        const char __user *s = user_buffer;
-        int m = (sizeof(data) - 1) / 3;
-        struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
+        struct usb_ftdi *ftdi = file->private_data;
+
         if (ftdi->disconnected > 0) {
                 return -ENODEV;
         }
@@ -1220,27 +1215,18 @@ static ssize_t ftdi_elan_write(struct file *file,
         if (retval) {
                 dev_err(&ftdi->udev->dev, "failed submitting write urb, error %"
                         "d\n", retval);
-                goto error_4;
+                goto error_3;
         }
         usb_free_urb(urb);
-      exit:;
-        if (count > m) {
-                int I = m - 1;
-                while (I-- > 0) {
-                        d += sprintf(d, " %02X", 0x000000FF & *s++);
-                }
-                d += sprintf(d, " ..");
-        } else {
-                int I = count;
-                while (I-- > 0) {
-                        d += sprintf(d, " %02X", 0x000000FF & *s++);
-                }
-        }
+
+exit:
         return count;
-      error_4: error_3:usb_buffer_free(ftdi->udev, count, buf,
-              urb->transfer_dma);
-      error_2:usb_free_urb(urb);
-      error_1:return retval;
+error_3:
+       usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma);
+error_2:
+       usb_free_urb(urb);
+error_1:
+       return retval;
 }
 
 static struct file_operations ftdi_elan_fops = {
diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c
new file mode 100644 (file)
index 0000000..33cd91d
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * PlayStation 2 Trance Vibrator driver
+ *
+ * Copyright (C) 2006 Sam Hocevar <sam@zoy.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Standard include files */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+/* Version Information */
+#define DRIVER_VERSION "v1.1"
+#define DRIVER_AUTHOR "Sam Hocevar, sam@zoy.org"
+#define DRIVER_DESC "PlayStation 2 Trance Vibrator driver"
+
+#define TRANCEVIBRATOR_VENDOR_ID       0x0b49  /* ASCII Corporation */
+#define TRANCEVIBRATOR_PRODUCT_ID      0x064f  /* Trance Vibrator */
+
+static struct usb_device_id id_table [] = {
+       { USB_DEVICE(TRANCEVIBRATOR_VENDOR_ID, TRANCEVIBRATOR_PRODUCT_ID) },
+       { },
+};
+MODULE_DEVICE_TABLE (usb, id_table);
+
+/* Driver-local specific stuff */
+struct trancevibrator {
+       struct usb_device *udev;
+       unsigned int speed;
+};
+
+static ssize_t show_speed(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct trancevibrator *tv = usb_get_intfdata(intf);
+
+       return sprintf(buf, "%d\n", tv->speed);
+}
+
+static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count)
+{
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct trancevibrator *tv = usb_get_intfdata(intf);
+       int temp, retval;
+
+       temp = simple_strtoul(buf, NULL, 10);
+       if (temp > 255)
+               temp = 255;
+       else if (temp < 0)
+               temp = 0;
+       tv->speed = temp;
+
+       dev_dbg(&tv->udev->dev, "speed = %d\n", tv->speed);
+
+       /* Set speed */
+       retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0),
+                                0x01, /* vendor request: set speed */
+                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                                tv->speed, /* speed value */
+                                0, NULL, 0, USB_CTRL_GET_TIMEOUT);
+       if (retval) {
+               dev_dbg(&tv->udev->dev, "retval = %d\n", retval);
+               return retval;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed);
+
+static int tv_probe(struct usb_interface *interface,
+                   const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct trancevibrator *dev;
+       int retval;
+
+       dev = kzalloc(sizeof(struct trancevibrator), GFP_KERNEL);
+       if (dev == NULL) {
+               dev_err(&interface->dev, "Out of memory\n");
+               retval = -ENOMEM;
+               goto error;
+       }
+
+       dev->udev = usb_get_dev(udev);
+       usb_set_intfdata(interface, dev);
+       retval = device_create_file(&interface->dev, &dev_attr_speed);
+       if (retval)
+               goto error_create_file;
+
+       return 0;
+
+error_create_file:
+       usb_put_dev(udev);
+       usb_set_intfdata(interface, NULL);
+error:
+       kfree(dev);
+       return retval;
+}
+
+static void tv_disconnect(struct usb_interface *interface)
+{
+       struct trancevibrator *dev;
+
+       dev = usb_get_intfdata (interface);
+       usb_set_intfdata(interface, NULL);
+       device_remove_file(&interface->dev, &dev_attr_speed);
+       usb_put_dev(dev->udev);
+       kfree(dev);
+}
+
+/* USB subsystem object */
+static struct usb_driver tv_driver = {
+       .name =         "trancevibrator",
+       .probe =        tv_probe,
+       .disconnect =   tv_disconnect,
+       .id_table =     id_table,
+};
+
+static int __init tv_init(void)
+{
+       int retval = usb_register(&tv_driver);
+       if (retval) {
+               err("usb_register failed. Error number %d", retval);
+               return retval;
+       }
+
+       info(DRIVER_VERSION ":" DRIVER_DESC);
+       return 0;
+}
+
+static void __exit tv_exit(void)
+{
+       usb_deregister(&tv_driver);
+}
+
+module_init (tv_init);
+module_exit (tv_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
index 054059632a219e54d2217486df8da039a7a0bff9..454a186b64ad1bafdd3b09738c1d787fd8d44415 100644 (file)
@@ -207,6 +207,14 @@ config USB_NET_PLUSB
          Choose this option if you're using a host-to-host cable
          with one of these chips.
 
+config USB_NET_MCS7830
+       tristate "MosChip MCS7830 based Ethernet adapters"
+       depends on USB_USBNET
+       help
+         Choose this option if you're using a 10/100 Ethernet USB2
+         adapter based on the MosChip 7830 controller. This includes
+         adapters marketed under the DeLOCK brand.
+
 config USB_NET_RNDIS_HOST
        tristate "Host for RNDIS devices (EXPERIMENTAL)"
        depends on USB_USBNET && EXPERIMENTAL
index 160f19dbdf121253ad360e8d64313aff8253d25d..7b51964de171416cc614c99c80b97f3494cdf841 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_PLUSB)   += plusb.o
 obj-$(CONFIG_USB_NET_RNDIS_HOST)       += rndis_host.o
 obj-$(CONFIG_USB_NET_CDC_SUBSET)       += cdc_subset.o
 obj-$(CONFIG_USB_NET_ZAURUS)   += zaurus.o
+obj-$(CONFIG_USB_NET_MCS7830)  += mcs7830.o
 obj-$(CONFIG_USB_USBNET)       += usbnet.o
 
 ifeq ($(CONFIG_USB_DEBUG),y)
index c73dd224aa76d2fc9ec0b1895b580a0725e849e8..881841e600def9f680f58109b30bfb175e4d2118 100644 (file)
@@ -569,10 +569,12 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
        struct usbnet *dev = netdev_priv(netdev);
        u16 res;
 
+       mutex_lock(&dev->phy_mutex);
        asix_set_sw_mii(dev);
        asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
                                (__u16)loc, 2, (u16 *)&res);
        asix_set_hw_mii(dev);
+       mutex_unlock(&dev->phy_mutex);
 
        devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff));
 
@@ -586,10 +588,12 @@ asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
        u16 res = cpu_to_le16(val);
 
        devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val);
+       mutex_lock(&dev->phy_mutex);
        asix_set_sw_mii(dev);
        asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
                                (__u16)loc, 2, (u16 *)&res);
        asix_set_hw_mii(dev);
+       mutex_unlock(&dev->phy_mutex);
 }
 
 /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
@@ -700,32 +704,6 @@ static void asix_get_drvinfo (struct net_device *net,
        info->eedump_len = data->eeprom_len;
 }
 
-static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
-{
-       struct usbnet *dev = netdev_priv(net);
-
-       return mii_ethtool_gset(&dev->mii,cmd);
-}
-
-static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
-{
-       struct usbnet *dev = netdev_priv(net);
-       int res = mii_ethtool_sset(&dev->mii,cmd);
-
-       /* link speed/duplex might have changed */
-       if (dev->driver_info->link_reset)
-               dev->driver_info->link_reset(dev);
-
-       return res;
-}
-
-static int asix_nway_reset(struct net_device *net)
-{
-       struct usbnet *dev = netdev_priv(net);
-
-       return mii_nway_restart(&dev->mii);
-}
-
 static u32 asix_get_link(struct net_device *net)
 {
        struct usbnet *dev = netdev_priv(net);
@@ -746,15 +724,15 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
 static struct ethtool_ops ax88172_ethtool_ops = {
        .get_drvinfo            = asix_get_drvinfo,
        .get_link               = asix_get_link,
-       .nway_reset             = asix_nway_reset,
        .get_msglevel           = usbnet_get_msglevel,
        .set_msglevel           = usbnet_set_msglevel,
        .get_wol                = asix_get_wol,
        .set_wol                = asix_set_wol,
        .get_eeprom_len         = asix_get_eeprom_len,
        .get_eeprom             = asix_get_eeprom,
-       .get_settings           = asix_get_settings,
-       .set_settings           = asix_set_settings,
+       .get_settings           = usbnet_get_settings,
+       .set_settings           = usbnet_set_settings,
+       .nway_reset             = usbnet_nway_reset,
 };
 
 static void ax88172_set_multicast(struct net_device *net)
@@ -885,15 +863,15 @@ out1:
 static struct ethtool_ops ax88772_ethtool_ops = {
        .get_drvinfo            = asix_get_drvinfo,
        .get_link               = asix_get_link,
-       .nway_reset             = asix_nway_reset,
        .get_msglevel           = usbnet_get_msglevel,
        .set_msglevel           = usbnet_set_msglevel,
        .get_wol                = asix_get_wol,
        .set_wol                = asix_set_wol,
        .get_eeprom_len         = asix_get_eeprom_len,
        .get_eeprom             = asix_get_eeprom,
-       .get_settings           = asix_get_settings,
-       .set_settings           = asix_set_settings,
+       .get_settings           = usbnet_get_settings,
+       .set_settings           = usbnet_set_settings,
+       .nway_reset             = usbnet_nway_reset,
 };
 
 static int ax88772_link_reset(struct usbnet *dev)
@@ -1046,15 +1024,15 @@ out1:
 static struct ethtool_ops ax88178_ethtool_ops = {
        .get_drvinfo            = asix_get_drvinfo,
        .get_link               = asix_get_link,
-       .nway_reset             = asix_nway_reset,
        .get_msglevel           = usbnet_get_msglevel,
        .set_msglevel           = usbnet_set_msglevel,
        .get_wol                = asix_get_wol,
        .set_wol                = asix_set_wol,
        .get_eeprom_len         = asix_get_eeprom_len,
        .get_eeprom             = asix_get_eeprom,
-       .get_settings           = asix_get_settings,
-       .set_settings           = asix_set_settings,
+       .get_settings           = usbnet_get_settings,
+       .set_settings           = usbnet_set_settings,
+       .nway_reset             = usbnet_nway_reset,
 };
 
 static int marvell_phy_init(struct usbnet *dev)
index 82ce0358d9a3e5f13e44a76089c319e28622b662..f6971b88349d8b8a3e5c4eec357ce2ed1063166b 100644 (file)
@@ -498,7 +498,7 @@ static struct usb_driver cdc_driver = {
 
 static int __init cdc_init(void)
 {
-       BUG_ON((sizeof(((struct usbnet *)0)->data)
+       BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
                        < sizeof(struct cdc_state)));
 
        return usb_register(&cdc_driver);
index 957d4ad316f9bf86f7636119bbc4b161a34ac9d1..7c906a43e4973b081b9cdd20d068913e43a930bd 100644 (file)
 
 #undef DEBUG
 
-#ifdef DEBUG
-#define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg)
-#else
-#define kaweth_dbg(format, arg...) do {} while (0)
-#endif
-#define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg)
-#define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg)
-#define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg)
-
-
 #include "kawethfw.h"
 
 #define KAWETH_MTU                     1514
@@ -86,6 +76,9 @@
 
 #define KAWETH_STATUS_BROKEN           0x0000001
 #define KAWETH_STATUS_CLOSING          0x0000002
+#define KAWETH_STATUS_SUSPENDING       0x0000004
+
+#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING)
 
 #define KAWETH_PACKET_FILTER_PROMISCUOUS       0x01
 #define KAWETH_PACKET_FILTER_ALL_MULTICAST     0x02
 #define STATE_MASK                             0x40
 #define        STATE_SHIFT                             5
 
+#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED)
+
 
 MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>");
 MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
@@ -128,6 +123,8 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
                                       unsigned int pipe,
                                       struct usb_ctrlrequest *cmd, void *data,
                                       int len, int timeout);
+static int kaweth_suspend(struct usb_interface *intf, pm_message_t message);
+static int kaweth_resume(struct usb_interface *intf);
 
 /****************************************************************
  *     usb_device_id
@@ -179,6 +176,8 @@ static struct usb_driver kaweth_driver = {
        .name =         driver_name,
        .probe =        kaweth_probe,
        .disconnect =   kaweth_disconnect,
+       .suspend =      kaweth_suspend,
+       .resume =       kaweth_resume,
        .id_table =     usb_klsi_table,
 };
 
@@ -222,6 +221,7 @@ struct kaweth_device
        int suspend_lowmem_rx;
        int suspend_lowmem_ctrl;
        int linkstate;
+       int opened;
        struct work_struct lowmem_work;
 
        struct usb_device *dev;
@@ -265,17 +265,17 @@ static int kaweth_control(struct kaweth_device *kaweth,
 {
        struct usb_ctrlrequest *dr;
 
-       kaweth_dbg("kaweth_control()");
+       dbg("kaweth_control()");
 
        if(in_interrupt()) {
-               kaweth_dbg("in_interrupt()");
+               dbg("in_interrupt()");
                return -EBUSY;
        }
 
        dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
 
        if (!dr) {
-               kaweth_dbg("kmalloc() failed");
+               dbg("kmalloc() failed");
                return -ENOMEM;
        }
 
@@ -300,7 +300,7 @@ static int kaweth_read_configuration(struct kaweth_device *kaweth)
 {
        int retval;
 
-       kaweth_dbg("Reading kaweth configuration");
+       dbg("Reading kaweth configuration");
 
        retval = kaweth_control(kaweth,
                                usb_rcvctrlpipe(kaweth->dev, 0),
@@ -322,7 +322,7 @@ static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size)
 {
        int retval;
 
-       kaweth_dbg("Setting URB size to %d", (unsigned)urb_size);
+       dbg("Setting URB size to %d", (unsigned)urb_size);
 
        retval = kaweth_control(kaweth,
                                usb_sndctrlpipe(kaweth->dev, 0),
@@ -344,7 +344,7 @@ static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait)
 {
        int retval;
 
-       kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait);
+       dbg("Set SOFS wait to %d", (unsigned)sofs_wait);
 
        retval = kaweth_control(kaweth,
                                usb_sndctrlpipe(kaweth->dev, 0),
@@ -367,7 +367,7 @@ static int kaweth_set_receive_filter(struct kaweth_device *kaweth,
 {
        int retval;
 
-       kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter);
+       dbg("Set receive filter to %d", (unsigned)receive_filter);
 
        retval = kaweth_control(kaweth,
                                usb_sndctrlpipe(kaweth->dev, 0),
@@ -392,7 +392,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
                                    __u8 type)
 {
        if(data_len > KAWETH_FIRMWARE_BUF_SIZE) {
-               kaweth_err("Firmware too big: %d", data_len);
+               err("Firmware too big: %d", data_len);
                return -ENOSPC;
        }
 
@@ -403,13 +403,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
        kaweth->firmware_buf[4] = type;
        kaweth->firmware_buf[5] = interrupt;
 
-       kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
+       dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
                   kaweth->firmware_buf[2]);
 
-       kaweth_dbg("Downloading firmware at %p to kaweth device at %p",
+       dbg("Downloading firmware at %p to kaweth device at %p",
            data,
            kaweth);
-       kaweth_dbg("Firmware length: %d", data_len);
+       dbg("Firmware length: %d", data_len);
 
        return kaweth_control(kaweth,
                              usb_sndctrlpipe(kaweth->dev, 0),
@@ -437,7 +437,7 @@ static int kaweth_trigger_firmware(struct kaweth_device *kaweth,
        kaweth->firmware_buf[6] = 0x00;
        kaweth->firmware_buf[7] = 0x00;
 
-       kaweth_dbg("Triggering firmware");
+       dbg("Triggering firmware");
 
        return kaweth_control(kaweth,
                              usb_sndctrlpipe(kaweth->dev, 0),
@@ -457,7 +457,7 @@ static int kaweth_reset(struct kaweth_device *kaweth)
 {
        int result;
 
-       kaweth_dbg("kaweth_reset(%p)", kaweth);
+       dbg("kaweth_reset(%p)", kaweth);
        result = kaweth_control(kaweth,
                                usb_sndctrlpipe(kaweth->dev, 0),
                                USB_REQ_SET_CONFIGURATION,
@@ -470,7 +470,7 @@ static int kaweth_reset(struct kaweth_device *kaweth)
 
        mdelay(10);
 
-       kaweth_dbg("kaweth_reset() returns %d.",result);
+       dbg("kaweth_reset() returns %d.",result);
 
        return result;
 }
@@ -534,7 +534,7 @@ static void kaweth_resubmit_tl(void *d)
 {
        struct kaweth_device *kaweth = (struct kaweth_device *)d;
 
-       if (kaweth->status | KAWETH_STATUS_CLOSING)
+       if (IS_BLOCKED(kaweth->status))
                return;
 
        if (kaweth->suspend_lowmem_rx)
@@ -568,7 +568,7 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
                        kaweth->suspend_lowmem_rx = 1;
                        schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
                }
-               kaweth_err("resubmitting rx_urb %d failed", result);
+               err("resubmitting rx_urb %d failed", result);
        } else {
                kaweth->suspend_lowmem_rx = 0;
        }
@@ -601,11 +601,15 @@ static void kaweth_usb_receive(struct urb *urb)
                return;
        }
 
-       if (kaweth->status & KAWETH_STATUS_CLOSING)
+       spin_lock(&kaweth->device_lock);
+       if (IS_BLOCKED(kaweth->status)) {
+               spin_unlock(&kaweth->device_lock);
                return;
+       }
+       spin_unlock(&kaweth->device_lock);
 
        if(urb->status && urb->status != -EREMOTEIO && count != 1) {
-               kaweth_err("%s RX status: %d count: %d packet_len: %d",
+               err("%s RX status: %d count: %d packet_len: %d",
                            net->name,
                           urb->status,
                           count,
@@ -616,9 +620,9 @@ static void kaweth_usb_receive(struct urb *urb)
 
        if(kaweth->net && (count > 2)) {
                if(pkt_len > (count - 2)) {
-                       kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
-                       kaweth_err("Packet len & 2047: %x", pkt_len & 2047);
-                       kaweth_err("Count 2: %x", count2);
+                       err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
+                       err("Packet len & 2047: %x", pkt_len & 2047);
+                       err("Count 2: %x", count2);
                        kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
                         return;
                 }
@@ -655,7 +659,7 @@ static int kaweth_open(struct net_device *net)
        struct kaweth_device *kaweth = netdev_priv(net);
        int res;
 
-       kaweth_dbg("Opening network device.");
+       dbg("Opening network device.");
 
        res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
        if (res)
@@ -678,6 +682,7 @@ static int kaweth_open(struct net_device *net)
                usb_kill_urb(kaweth->rx_urb);
                return -EIO;
        }
+       kaweth->opened = 1;
 
        netif_start_queue(net);
 
@@ -688,14 +693,8 @@ static int kaweth_open(struct net_device *net)
 /****************************************************************
  *     kaweth_close
  ****************************************************************/
-static int kaweth_close(struct net_device *net)
+static void kaweth_kill_urbs(struct kaweth_device *kaweth)
 {
-       struct kaweth_device *kaweth = netdev_priv(net);
-
-       netif_stop_queue(net);
-
-       kaweth->status |= KAWETH_STATUS_CLOSING;
-
        usb_kill_urb(kaweth->irq_urb);
        usb_kill_urb(kaweth->rx_urb);
        usb_kill_urb(kaweth->tx_urb);
@@ -706,6 +705,21 @@ static int kaweth_close(struct net_device *net)
           we hit them again */
        usb_kill_urb(kaweth->irq_urb);
        usb_kill_urb(kaweth->rx_urb);
+}
+
+/****************************************************************
+ *     kaweth_close
+ ****************************************************************/
+static int kaweth_close(struct net_device *net)
+{
+       struct kaweth_device *kaweth = netdev_priv(net);
+
+       netif_stop_queue(net);
+       kaweth->opened = 0;
+
+       kaweth->status |= KAWETH_STATUS_CLOSING;
+
+       kaweth_kill_urbs(kaweth);
 
        kaweth->status &= ~KAWETH_STATUS_CLOSING;
 
@@ -732,7 +746,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb)
 
        if (unlikely(urb->status != 0))
                if (urb->status != -ENOENT)
-                       kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
+                       dbg("%s: TX status %d.", kaweth->net->name, urb->status);
 
        netif_wake_queue(kaweth->net);
        dev_kfree_skb_irq(skb);
@@ -752,6 +766,9 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
 
        kaweth_async_set_rx_mode(kaweth);
        netif_stop_queue(net);
+       if (IS_BLOCKED(kaweth->status)) {
+               goto skip;
+       }
 
        /* We now decide whether we can put our special header into the sk_buff */
        if (skb_cloned(skb) || skb_headroom(skb) < 2) {
@@ -783,7 +800,8 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
 
        if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
        {
-               kaweth_warn("kaweth failed tx_urb %d", res);
+               warn("kaweth failed tx_urb %d", res);
+skip:
                kaweth->stats.tx_errors++;
 
                netif_start_queue(net);
@@ -812,7 +830,7 @@ static void kaweth_set_rx_mode(struct net_device *net)
                                      KAWETH_PACKET_FILTER_BROADCAST |
                                     KAWETH_PACKET_FILTER_MULTICAST;
 
-       kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap);
+       dbg("Setting Rx mode to %d", packet_filter_bitmap);
 
        netif_stop_queue(net);
 
@@ -850,10 +868,10 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
                                KAWETH_CONTROL_TIMEOUT);
 
        if(result < 0) {
-               kaweth_err("Failed to set Rx mode: %d", result);
+               err("Failed to set Rx mode: %d", result);
        }
        else {
-               kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap);
+               dbg("Set Rx mode to %d", packet_filter_bitmap);
        }
        }
 }
@@ -874,13 +892,49 @@ static void kaweth_tx_timeout(struct net_device *net)
 {
        struct kaweth_device *kaweth = netdev_priv(net);
 
-       kaweth_warn("%s: Tx timed out. Resetting.", net->name);
+       warn("%s: Tx timed out. Resetting.", net->name);
        kaweth->stats.tx_errors++;
        net->trans_start = jiffies;
 
        usb_unlink_urb(kaweth->tx_urb);
 }
 
+/****************************************************************
+ *     kaweth_suspend
+ ****************************************************************/
+static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct kaweth_device *kaweth = usb_get_intfdata(intf);
+       unsigned long flags;
+
+       spin_lock_irqsave(&kaweth->device_lock, flags);
+       kaweth->status |= KAWETH_STATUS_SUSPENDING;
+       spin_unlock_irqrestore(&kaweth->device_lock, flags);
+
+       kaweth_kill_urbs(kaweth);
+       return 0;
+}
+
+/****************************************************************
+ *     kaweth_resume
+ ****************************************************************/
+static int kaweth_resume(struct usb_interface *intf)
+{
+       struct kaweth_device *kaweth = usb_get_intfdata(intf);
+       unsigned long flags;
+
+       spin_lock_irqsave(&kaweth->device_lock, flags);
+       kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
+       spin_unlock_irqrestore(&kaweth->device_lock, flags);
+
+       if (!kaweth->opened)
+               return 0;
+       kaweth_resubmit_rx_urb(kaweth, GFP_NOIO);
+       kaweth_resubmit_int_urb(kaweth, GFP_NOIO);
+
+       return 0;
+}
+
 /****************************************************************
  *     kaweth_probe
  ****************************************************************/
@@ -895,15 +949,15 @@ static int kaweth_probe(
        const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
        int result = 0;
 
-       kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
+       dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
                 dev->devnum,
                 le16_to_cpu(dev->descriptor.idVendor),
                 le16_to_cpu(dev->descriptor.idProduct),
                 le16_to_cpu(dev->descriptor.bcdDevice));
 
-       kaweth_dbg("Device at %p", dev);
+       dbg("Device at %p", dev);
 
-       kaweth_dbg("Descriptor length: %x type: %x",
+       dbg("Descriptor length: %x type: %x",
                 (int)dev->descriptor.bLength,
                 (int)dev->descriptor.bDescriptorType);
 
@@ -918,7 +972,7 @@ static int kaweth_probe(
        spin_lock_init(&kaweth->device_lock);
        init_waitqueue_head(&kaweth->term_wait);
 
-       kaweth_dbg("Resetting.");
+       dbg("Resetting.");
 
        kaweth_reset(kaweth);
 
@@ -928,17 +982,17 @@ static int kaweth_probe(
         */
 
        if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) {
-               kaweth_info("Firmware present in device.");
+               info("Firmware present in device.");
        } else {
                /* Download the firmware */
-               kaweth_info("Downloading firmware...");
+               info("Downloading firmware...");
                kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL);
                if ((result = kaweth_download_firmware(kaweth,
                                                      kaweth_new_code,
                                                      len_kaweth_new_code,
                                                      100,
                                                      2)) < 0) {
-                       kaweth_err("Error downloading firmware (%d)", result);
+                       err("Error downloading firmware (%d)", result);
                        goto err_fw;
                }
 
@@ -947,7 +1001,7 @@ static int kaweth_probe(
                                                      len_kaweth_new_code_fix,
                                                      100,
                                                      3)) < 0) {
-                       kaweth_err("Error downloading firmware fix (%d)", result);
+                       err("Error downloading firmware fix (%d)", result);
                        goto err_fw;
                }
 
@@ -956,7 +1010,7 @@ static int kaweth_probe(
                                                      len_kaweth_trigger_code,
                                                      126,
                                                      2)) < 0) {
-                       kaweth_err("Error downloading trigger code (%d)", result);
+                       err("Error downloading trigger code (%d)", result);
                        goto err_fw;
 
                }
@@ -966,18 +1020,18 @@ static int kaweth_probe(
                                                      len_kaweth_trigger_code_fix,
                                                      126,
                                                      3)) < 0) {
-                       kaweth_err("Error downloading trigger code fix (%d)", result);
+                       err("Error downloading trigger code fix (%d)", result);
                        goto err_fw;
                }
 
 
                if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
-                       kaweth_err("Error triggering firmware (%d)", result);
+                       err("Error triggering firmware (%d)", result);
                        goto err_fw;
                }
 
                /* Device will now disappear for a moment...  */
-               kaweth_info("Firmware loaded.  I'll be back...");
+               info("Firmware loaded.  I'll be back...");
 err_fw:
                free_page((unsigned long)kaweth->firmware_buf);
                free_netdev(netdev);
@@ -987,14 +1041,14 @@ err_fw:
        result = kaweth_read_configuration(kaweth);
 
        if(result < 0) {
-               kaweth_err("Error reading configuration (%d), no net device created", result);
+               err("Error reading configuration (%d), no net device created", result);
                goto err_free_netdev;
        }
 
-       kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask);
-       kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
-       kaweth_info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size));
-       kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+       info("Statistics collection: %x", kaweth->configuration.statistics_mask);
+       info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
+       info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size));
+       info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
                 (int)kaweth->configuration.hw_addr[0],
                 (int)kaweth->configuration.hw_addr[1],
                 (int)kaweth->configuration.hw_addr[2],
@@ -1005,17 +1059,17 @@ err_fw:
        if(!memcmp(&kaweth->configuration.hw_addr,
                    &bcast_addr,
                   sizeof(bcast_addr))) {
-               kaweth_err("Firmware not functioning properly, no net device created");
+               err("Firmware not functioning properly, no net device created");
                goto err_free_netdev;
        }
 
        if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) {
-               kaweth_dbg("Error setting URB size");
+               dbg("Error setting URB size");
                goto err_free_netdev;
        }
 
        if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
-               kaweth_err("Error setting SOFS wait");
+               err("Error setting SOFS wait");
                goto err_free_netdev;
        }
 
@@ -1025,11 +1079,11 @@ err_fw:
                                            KAWETH_PACKET_FILTER_MULTICAST);
 
        if(result < 0) {
-               kaweth_err("Error setting receive filter");
+               err("Error setting receive filter");
                goto err_free_netdev;
        }
 
-       kaweth_dbg("Initializing net device.");
+       dbg("Initializing net device.");
 
        kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!kaweth->tx_urb)
@@ -1086,13 +1140,13 @@ err_fw:
 
        SET_NETDEV_DEV(netdev, &intf->dev);
        if (register_netdev(netdev) != 0) {
-               kaweth_err("Error registering netdev.");
+               err("Error registering netdev.");
                goto err_intfdata;
        }
 
-       kaweth_info("kaweth interface created at %s", kaweth->net->name);
+       info("kaweth interface created at %s", kaweth->net->name);
 
-       kaweth_dbg("Kaweth probe returning.");
+       dbg("Kaweth probe returning.");
 
        return 0;
 
@@ -1121,16 +1175,16 @@ static void kaweth_disconnect(struct usb_interface *intf)
        struct kaweth_device *kaweth = usb_get_intfdata(intf);
        struct net_device *netdev;
 
-       kaweth_info("Unregistering");
+       info("Unregistering");
 
        usb_set_intfdata(intf, NULL);
        if (!kaweth) {
-               kaweth_warn("unregistering non-existant device");
+               warn("unregistering non-existant device");
                return;
        }
        netdev = kaweth->net;
 
-       kaweth_dbg("Unregistering net device");
+       dbg("Unregistering net device");
        unregister_netdev(netdev);
 
        usb_free_urb(kaweth->rx_urb);
@@ -1185,7 +1239,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
 
        if (!wait_event_timeout(awd.wqh, awd.done, timeout)) {
                 // timeout
-                kaweth_warn("usb_control/bulk_msg: timeout");
+                warn("usb_control/bulk_msg: timeout");
                 usb_kill_urb(urb);  // remove urb safely
                 status = -ETIMEDOUT;
         }
@@ -1234,7 +1288,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
  ****************************************************************/
 static int __init kaweth_init(void)
 {
-       kaweth_dbg("Driver loading");
+       dbg("Driver loading");
        return usb_register(&kaweth_driver);
 }
 
diff --git a/drivers/usb/net/mcs7830.c b/drivers/usb/net/mcs7830.c
new file mode 100644 (file)
index 0000000..6240b97
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * MosChips MCS7830 based USB 2.0 Ethernet Devices
+ *
+ * based on usbnet.c, asix.c and the vendor provided mcs7830 driver
+ *
+ * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * Copyright (c) 2002-2003 TiVo Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/crc32.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "usbnet.h"
+
+/* requests */
+#define MCS7830_RD_BMREQ       (USB_DIR_IN  | USB_TYPE_VENDOR | \
+                                USB_RECIP_DEVICE)
+#define MCS7830_WR_BMREQ       (USB_DIR_OUT | USB_TYPE_VENDOR | \
+                                USB_RECIP_DEVICE)
+#define MCS7830_RD_BREQ                0x0E
+#define MCS7830_WR_BREQ                0x0D
+
+#define MCS7830_CTRL_TIMEOUT   1000
+#define MCS7830_MAX_MCAST      64
+
+#define MCS7830_VENDOR_ID      0x9710
+#define MCS7830_PRODUCT_ID     0x7830
+
+#define MCS7830_MII_ADVERTISE  (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \
+                                ADVERTISE_100HALF | ADVERTISE_10FULL | \
+                                ADVERTISE_10HALF | ADVERTISE_CSMA)
+
+/* HIF_REG_XX coressponding index value */
+enum {
+       HIF_REG_MULTICAST_HASH                  = 0x00,
+       HIF_REG_PACKET_GAP1                     = 0x08,
+       HIF_REG_PACKET_GAP2                     = 0x09,
+       HIF_REG_PHY_DATA                        = 0x0a,
+       HIF_REG_PHY_CMD1                        = 0x0c,
+          HIF_REG_PHY_CMD1_READ                = 0x40,
+          HIF_REG_PHY_CMD1_WRITE               = 0x20,
+          HIF_REG_PHY_CMD1_PHYADDR             = 0x01,
+       HIF_REG_PHY_CMD2                        = 0x0d,
+          HIF_REG_PHY_CMD2_PEND_FLAG_BIT       = 0x80,
+          HIF_REG_PHY_CMD2_READY_FLAG_BIT      = 0x40,
+       HIF_REG_CONFIG                          = 0x0e,
+          HIF_REG_CONFIG_CFG                   = 0x80,
+          HIF_REG_CONFIG_SPEED100              = 0x40,
+          HIF_REG_CONFIG_FULLDUPLEX_ENABLE     = 0x20,
+          HIF_REG_CONFIG_RXENABLE              = 0x10,
+          HIF_REG_CONFIG_TXENABLE              = 0x08,
+          HIF_REG_CONFIG_SLEEPMODE             = 0x04,
+          HIF_REG_CONFIG_ALLMULTICAST          = 0x02,
+          HIF_REG_CONFIG_PROMISCIOUS           = 0x01,
+       HIF_REG_ETHERNET_ADDR                   = 0x0f,
+       HIF_REG_22                              = 0x15,
+       HIF_REG_PAUSE_THRESHOLD                 = 0x16,
+          HIF_REG_PAUSE_THRESHOLD_DEFAULT      = 0,
+};
+
+struct mcs7830_data {
+       u8 multi_filter[8];
+       u8 config;
+};
+
+static const char driver_name[] = "MOSCHIP usb-ethernet driver";
+
+static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
+{
+       struct usb_device *xdev = dev->udev;
+       int ret;
+
+       ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ,
+                             MCS7830_RD_BMREQ, 0x0000, index, data,
+                             size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
+       return ret;
+}
+
+static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data)
+{
+       struct usb_device *xdev = dev->udev;
+       int ret;
+
+       ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ,
+                             MCS7830_WR_BMREQ, 0x0000, index, data,
+                             size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
+       return ret;
+}
+
+static void mcs7830_async_cmd_callback(struct urb *urb)
+{
+       struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+
+       if (urb->status < 0)
+               printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d",
+                       urb->status);
+
+       kfree(req);
+       usb_free_urb(urb);
+}
+
+static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data)
+{
+       struct usb_ctrlrequest *req;
+       int ret;
+       struct urb *urb;
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb) {
+               dev_dbg(&dev->udev->dev, "Error allocating URB "
+                               "in write_cmd_async!");
+               return;
+       }
+
+       req = kmalloc(sizeof *req, GFP_ATOMIC);
+       if (!req) {
+               dev_err(&dev->udev->dev, "Failed to allocate memory for "
+                               "control request");
+               goto out;
+       }
+       req->bRequestType = MCS7830_WR_BMREQ;
+       req->bRequest = MCS7830_WR_BREQ;
+       req->wValue = 0;
+       req->wIndex = cpu_to_le16(index);
+       req->wLength = cpu_to_le16(size);
+
+       usb_fill_control_urb(urb, dev->udev,
+                            usb_sndctrlpipe(dev->udev, 0),
+                            (void *)req, data, size,
+                            mcs7830_async_cmd_callback, req);
+
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       if (ret < 0) {
+               dev_err(&dev->udev->dev, "Error submitting the control "
+                               "message: ret=%d", ret);
+               goto out;
+       }
+       return;
+out:
+       kfree(req);
+       usb_free_urb(urb);
+}
+
+static int mcs7830_get_address(struct usbnet *dev)
+{
+       int ret;
+       ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
+                                  dev->net->dev_addr);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static int mcs7830_read_phy(struct usbnet *dev, u8 index)
+{
+       int ret;
+       int i;
+       __le16 val;
+
+       u8 cmd[2] = {
+               HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR,
+               HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index,
+       };
+
+       mutex_lock(&dev->phy_mutex);
+       /* write the MII command */
+       ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
+       if (ret < 0)
+               goto out;
+
+       /* wait for the data to become valid, should be within < 1ms */
+       for (i = 0; i < 10; i++) {
+               ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
+               if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
+                       break;
+               ret = -EIO;
+               msleep(1);
+       }
+       if (ret < 0)
+               goto out;
+
+       /* read actual register contents */
+       ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val);
+       if (ret < 0)
+               goto out;
+       ret = le16_to_cpu(val);
+       dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n",
+               index, val, i);
+out:
+       mutex_unlock(&dev->phy_mutex);
+       return ret;
+}
+
+static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val)
+{
+       int ret;
+       int i;
+       __le16 le_val;
+
+       u8 cmd[2] = {
+               HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR,
+               HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F),
+       };
+
+       mutex_lock(&dev->phy_mutex);
+
+       /* write the new register contents */
+       le_val = cpu_to_le16(val);
+       ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val);
+       if (ret < 0)
+               goto out;
+
+       /* write the MII command */
+       ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
+       if (ret < 0)
+               goto out;
+
+       /* wait for the command to be accepted by the PHY */
+       for (i = 0; i < 10; i++) {
+               ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
+               if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
+                       break;
+               ret = -EIO;
+               msleep(1);
+       }
+       if (ret < 0)
+               goto out;
+
+       ret = 0;
+       dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n",
+               index, val, i);
+out:
+       mutex_unlock(&dev->phy_mutex);
+       return ret;
+}
+
+/*
+ * This algorithm comes from the original mcs7830 version 1.4 driver,
+ * not sure if it is needed.
+ */
+static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode)
+{
+       int ret;
+       /* Enable all media types */
+       ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE);
+
+       /* First reset BMCR */
+       if (!ret)
+               ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000);
+       /* Enable Auto Neg */
+       if (!ret)
+               ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE);
+       /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */
+       if (!ret)
+               ret = mcs7830_write_phy(dev, MII_BMCR,
+                               BMCR_ANENABLE | BMCR_ANRESTART  );
+       return ret < 0 ? : 0;
+}
+
+
+/*
+ * if we can read register 22, the chip revision is C or higher
+ */
+static int mcs7830_get_rev(struct usbnet *dev)
+{
+       u8 dummy[2];
+       int ret;
+       ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy);
+       if (ret > 0)
+               return 2; /* Rev C or later */
+       return 1; /* earlier revision */
+}
+
+/*
+ * On rev. C we need to set the pause threshold
+ */
+static void mcs7830_rev_C_fixup(struct usbnet *dev)
+{
+       u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT;
+       int retry;
+
+       for (retry = 0; retry < 2; retry++) {
+               if (mcs7830_get_rev(dev) == 2) {
+                       dev_info(&dev->udev->dev, "applying rev.C fixup\n");
+                       mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD,
+                                       1, &pause_threshold);
+               }
+               msleep(1);
+       }
+}
+
+static int mcs7830_init_dev(struct usbnet *dev)
+{
+       int ret;
+       int retry;
+
+       /* Read MAC address from EEPROM */
+       ret = -EINVAL;
+       for (retry = 0; retry < 5 && ret; retry++)
+               ret = mcs7830_get_address(dev);
+       if (ret) {
+               dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
+               goto out;
+       }
+
+       /* Set up PHY */
+       ret = mcs7830_set_autoneg(dev, 0);
+       if (ret) {
+               dev_info(&dev->udev->dev, "Cannot set autoneg\n");
+               goto out;
+       }
+
+       mcs7830_rev_C_fixup(dev);
+       ret = 0;
+out:
+       return ret;
+}
+
+static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
+                            int location)
+{
+       struct usbnet *dev = netdev->priv;
+       return mcs7830_read_phy(dev, location);
+}
+
+static void mcs7830_mdio_write(struct net_device *netdev, int phy_id,
+                               int location, int val)
+{
+       struct usbnet *dev = netdev->priv;
+       mcs7830_write_phy(dev, location, val);
+}
+
+static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+       struct usbnet *dev = netdev_priv(net);
+       return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+/* credits go to asix_set_multicast */
+static void mcs7830_set_multicast(struct net_device *net)
+{
+       struct usbnet *dev = netdev_priv(net);
+       struct mcs7830_data *data = (struct mcs7830_data *)&dev->data;
+
+       data->config = HIF_REG_CONFIG_TXENABLE;
+
+       /* this should not be needed, but it doesn't work otherwise */
+       data->config |= HIF_REG_CONFIG_ALLMULTICAST;
+
+       if (net->flags & IFF_PROMISC) {
+               data->config |= HIF_REG_CONFIG_PROMISCIOUS;
+       } else if (net->flags & IFF_ALLMULTI
+                  || net->mc_count > MCS7830_MAX_MCAST) {
+               data->config |= HIF_REG_CONFIG_ALLMULTICAST;
+       } else if (net->mc_count == 0) {
+               /* just broadcast and directed */
+       } else {
+               /* We use the 20 byte dev->data
+                * for our 8 byte filter buffer
+                * to avoid allocating memory that
+                * is tricky to free later */
+               struct dev_mc_list *mc_list = net->mc_list;
+               u32 crc_bits;
+               int i;
+
+               memset(data->multi_filter, 0, sizeof data->multi_filter);
+
+               /* Build the multicast hash filter. */
+               for (i = 0; i < net->mc_count; i++) {
+                       crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
+                       data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
+                       mc_list = mc_list->next;
+               }
+
+               mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
+                               sizeof data->multi_filter,
+                               data->multi_filter);
+       }
+
+       mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
+}
+
+static int mcs7830_get_regs_len(struct net_device *net)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       switch (mcs7830_get_rev(dev)) {
+       case 1:
+               return 21;
+       case 2:
+               return 32;
+       }
+       return 0;
+}
+
+static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo)
+{
+       usbnet_get_drvinfo(net, drvinfo);
+       drvinfo->regdump_len = mcs7830_get_regs_len(net);
+}
+
+static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       regs->version = mcs7830_get_rev(dev);
+       mcs7830_get_reg(dev, 0, regs->len, data);
+}
+
+static struct ethtool_ops mcs7830_ethtool_ops = {
+       .get_drvinfo            = mcs7830_get_drvinfo,
+       .get_regs_len           = mcs7830_get_regs_len,
+       .get_regs               = mcs7830_get_regs,
+
+       /* common usbnet calls */
+       .get_link               = usbnet_get_link,
+       .get_msglevel           = usbnet_get_msglevel,
+       .set_msglevel           = usbnet_set_msglevel,
+       .get_settings           = usbnet_get_settings,
+       .set_settings           = usbnet_set_settings,
+       .nway_reset             = usbnet_nway_reset,
+};
+
+static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
+{
+       struct net_device *net = dev->net;
+       int ret;
+
+       ret = mcs7830_init_dev(dev);
+       if (ret)
+               goto out;
+
+       net->do_ioctl = mcs7830_ioctl;
+       net->ethtool_ops = &mcs7830_ethtool_ops;
+       net->set_multicast_list = mcs7830_set_multicast;
+       mcs7830_set_multicast(net);
+
+       /* reserve space for the status byte on rx */
+       dev->rx_urb_size = ETH_FRAME_LEN + 1;
+
+       dev->mii.mdio_read = mcs7830_mdio_read;
+       dev->mii.mdio_write = mcs7830_mdio_write;
+       dev->mii.dev = net;
+       dev->mii.phy_id_mask = 0x3f;
+       dev->mii.reg_num_mask = 0x1f;
+       dev->mii.phy_id = *((u8 *) net->dev_addr + 1);
+
+       ret = usbnet_get_endpoints(dev, udev);
+out:
+       return ret;
+}
+
+/* The chip always appends a status bytes that we need to strip */
+static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+       u8 status;
+
+       if (skb->len == 0) {
+               dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
+               return 0;
+       }
+
+       skb_trim(skb, skb->len - 1);
+       status = skb->data[skb->len];
+
+       if (status != 0x20)
+               dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status);
+
+       return skb->len > 0;
+}
+
+static const struct driver_info moschip_info = {
+       .description    = "MOSCHIP 7830 usb-NET adapter",
+       .bind           = mcs7830_bind,
+       .rx_fixup       = mcs7830_rx_fixup,
+       .flags          = FLAG_ETHER,
+       .in             = 1,
+       .out            = 2,
+};
+
+static const struct usb_device_id products[] = {
+       {
+               USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID),
+               .driver_info = (unsigned long) &moschip_info,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver mcs7830_driver = {
+       .name = driver_name,
+       .id_table = products,
+       .probe = usbnet_probe,
+       .disconnect = usbnet_disconnect,
+       .suspend = usbnet_suspend,
+       .resume = usbnet_resume,
+};
+
+static int __init mcs7830_init(void)
+{
+       return usb_register(&mcs7830_driver);
+}
+module_init(mcs7830_init);
+
+static void __exit mcs7830_exit(void)
+{
+       usb_deregister(&mcs7830_driver);
+}
+module_exit(mcs7830_exit);
+
+MODULE_DESCRIPTION("USB to network adapter MCS7830)");
+MODULE_LICENSE("GPL");
index 24bd3486ee6334d45737c87345126c681bd97ad8..cf3d20eb781cde127e53f1af4c553bea198fa13a 100644 (file)
@@ -669,6 +669,37 @@ done:
  * they'll probably want to use this base set.
  */
 
+int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       if (!dev->mii.mdio_read)
+               return -EOPNOTSUPP;
+
+       return mii_ethtool_gset(&dev->mii, cmd);
+}
+EXPORT_SYMBOL_GPL(usbnet_get_settings);
+
+int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd)
+{
+       struct usbnet *dev = netdev_priv(net);
+       int retval;
+
+       if (!dev->mii.mdio_write)
+               return -EOPNOTSUPP;
+
+       retval = mii_ethtool_sset(&dev->mii, cmd);
+
+       /* link speed/duplex might have changed */
+       if (dev->driver_info->link_reset)
+               dev->driver_info->link_reset(dev);
+
+       return retval;
+
+}
+EXPORT_SYMBOL_GPL(usbnet_set_settings);
+
+
 void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
 {
        struct usbnet *dev = netdev_priv(net);
@@ -682,7 +713,7 @@ void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
 }
 EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);
 
-static u32 usbnet_get_link (struct net_device *net)
+u32 usbnet_get_link (struct net_device *net)
 {
        struct usbnet *dev = netdev_priv(net);
 
@@ -690,9 +721,14 @@ static u32 usbnet_get_link (struct net_device *net)
        if (dev->driver_info->check_connect)
                return dev->driver_info->check_connect (dev) == 0;
 
+       /* if the device has mii operations, use those */
+       if (dev->mii.mdio_read)
+               return mii_link_ok(&dev->mii);
+
        /* Otherwise, say we're up (to avoid breaking scripts) */
        return 1;
 }
+EXPORT_SYMBOL_GPL(usbnet_get_link);
 
 u32 usbnet_get_msglevel (struct net_device *net)
 {
@@ -710,10 +746,24 @@ void usbnet_set_msglevel (struct net_device *net, u32 level)
 }
 EXPORT_SYMBOL_GPL(usbnet_set_msglevel);
 
+int usbnet_nway_reset(struct net_device *net)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       if (!dev->mii.mdio_write)
+               return -EOPNOTSUPP;
+
+       return mii_nway_restart(&dev->mii);
+}
+EXPORT_SYMBOL_GPL(usbnet_nway_reset);
+
 /* drivers may override default ethtool_ops in their bind() routine */
 static struct ethtool_ops usbnet_ethtool_ops = {
+       .get_settings           = usbnet_get_settings,
+       .set_settings           = usbnet_set_settings,
        .get_drvinfo            = usbnet_get_drvinfo,
        .get_link               = usbnet_get_link,
+       .nway_reset             = usbnet_nway_reset,
        .get_msglevel           = usbnet_get_msglevel,
        .set_msglevel           = usbnet_set_msglevel,
 };
@@ -1094,6 +1144,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        dev->delay.function = usbnet_bh;
        dev->delay.data = (unsigned long) dev;
        init_timer (&dev->delay);
+       mutex_init (&dev->phy_mutex);
 
        SET_MODULE_OWNER (net);
        dev->net = net;
@@ -1225,7 +1276,7 @@ EXPORT_SYMBOL_GPL(usbnet_resume);
 static int __init usbnet_init(void)
 {
        /* compiler should optimize this out */
-       BUG_ON (sizeof (((struct sk_buff *)0)->cb)
+       BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb)
                        < sizeof (struct skb_data));
 
        random_ether_addr(node_id);
index c0746f0454afe277e4d970e81f6f36ea48305b25..07c70abbe0ecaa5c3df76e488239e79e0f7ebbcf 100644 (file)
@@ -30,6 +30,7 @@ struct usbnet {
        struct usb_device       *udev;
        struct driver_info      *driver_info;
        wait_queue_head_t       *wait;
+       struct mutex            phy_mutex;
 
        /* i/o info: pipes etc */
        unsigned                in, out;
@@ -168,9 +169,13 @@ extern void usbnet_defer_kevent (struct usbnet *, int);
 extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
 extern void usbnet_unlink_rx_urbs(struct usbnet *);
 
+extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd);
+extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd);
+extern u32 usbnet_get_link (struct net_device *net);
 extern u32 usbnet_get_msglevel (struct net_device *);
 extern void usbnet_set_msglevel (struct net_device *, u32);
 extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
+extern int usbnet_nway_reset(struct net_device *net);
 
 /* messaging support includes the interface name, so it must not be
  * used before it has one ... notably, in minidriver bind() calls.
index 5076b9d97057aee810faf064414485eec2f475e9..9a6ec1b5e3d5d1c1eca4dbbb3d70e56eb1ac4361 100644 (file)
@@ -422,6 +422,16 @@ config USB_SERIAL_MCT_U232
          To compile this driver as a module, choose M here: the
          module will be called mct_u232.
 
+config USB_SERIAL_MOS7720
+       tristate "USB Moschip 7720 Single Port Serial Driver"
+       depends on USB_SERIAL
+       ---help---
+         Say Y here if you want to use a USB Serial single port adapter from
+         Moschip Semiconductor Tech.
+
+         To compile this driver as a module, choose M here: the
+         module will be called mos7720.
+
 config USB_SERIAL_MOS7840
        tristate "USB Moschip 7840/7820 USB Serial Driver"
        depends on USB_SERIAL
@@ -527,8 +537,7 @@ config USB_SERIAL_OPTION
          The USB bus on these cards is not accessible externally.
 
          Supported devices include (some of?) those made by:
-         Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or
-         Anydata.
+         Option, Huawei, Audiovox, Novatel Wireless, or Anydata.
 
          To compile this driver as a module, choose M here: the
          module will be called option.
index 8dce83340e3109aa655d84512524f82510fe48cf..a5047dc599bbf738cbbb4a87352bf7bb638f25d3 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA)          += keyspan_pda.o
 obj-$(CONFIG_USB_SERIAL_KLSI)                  += kl5kusb105.o
 obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)             += kobil_sct.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)              += mct_u232.o
+obj-$(CONFIG_USB_SERIAL_MOS7720)               += mos7720.o
 obj-$(CONFIG_USB_SERIAL_MOS7840)               += mos7840.o
 obj-$(CONFIG_USB_SERIAL_NAVMAN)                        += navman.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)               += omninet.o
index 2c19f19b255cf48498311c59624f61d72cc1db42..7f5d546da39af963b57123b9b35e58e714a88cd0 100644 (file)
 
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
-       { USB_DEVICE(0x0f3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */
-       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
-       { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
-       { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
-       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
+       { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */
        { },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -133,6 +129,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
                }
                urb = usb_alloc_urb(0, GFP_KERNEL);
                if (!urb) {
+                       kfree(buffer);
                        dev_err(&port->dev, "%s - no more urbs?\n",
                                __FUNCTION__);
                        result = -ENOMEM;
index 486c7411b9a7572f3e573e494d2f903cd935e342..bbf6532c26e5328b43ce4abb7a4de319ce86fbb3 100644 (file)
@@ -65,6 +65,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
        { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
+       { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
        { } /* Terminating Entry */
 };
index d3dc1a15ec6ceacfe985d5b0a4640a34c8cb44c2..bd76b4c11fcc1dc12c3a8515002d7847f179d91e 100644 (file)
@@ -1,16 +1,16 @@
 /*
  * USB FTDI SIO driver
  *
- *     Copyright (C) 1999 - 2001
- *         Greg Kroah-Hartman (greg@kroah.com)
+ *     Copyright (C) 1999 - 2001
+ *         Greg Kroah-Hartman (greg@kroah.com)
  *          Bill Ryder (bryder@sgi.com)
  *     Copyright (C) 2002
  *         Kuba Ober (kuba@mareimbrium.org)
  *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
@@ -32,7 +32,7 @@
  *      Changed full name of USB-UIRT device to avoid "/" character.
  *      Added FTDI's alternate PID (0x6006) for FT232/245 devices.
  *      Added PID for "ELV USB Module UO100" from Stefan Frings.
- * 
+ *
  * (21/Oct/2003) Ian Abbott
  *      Renamed some VID/PID macros for Matrix Orbital and Perle Systems
  *      devices.  Removed Matrix Orbital and Perle Systems devices from the
@@ -69,7 +69,7 @@
  *     does not incure any measurable overhead.  This also relies on the fact
  *     that we have proper reference counting logic for urbs.  I nicked this
  *     from Greg KH's Visor driver.
- *      
+ *
  * (23/Jun/2003) Ian Abbott
  *      Reduced flip buffer pushes and corrected a data length test in
  *      ftdi_read_bulk_callback.
@@ -77,7 +77,7 @@
  *
  * (21/Jun/2003) Erik Nygren
  *      Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip.
- *      See <http://www.home-electro.com/tira1.htm>.  Only operates properly 
+ *      See <http://www.home-electro.com/tira1.htm>.  Only operates properly
  *      at 100000 and RTS-CTS, so set custom divisor mode on startup.
  *      Also force the Tira-1 and USB-UIRT to only use their custom baud rates.
  *
  * (17/Feb/2003) Bill Ryder
  *      Added write urb buffer pool on a per device basis
  *      Added more checking for open file on callbacks (fixed OOPS)
- *      Added CrystalFontz 632 and 634 PIDs 
+ *      Added CrystalFontz 632 and 634 PIDs
  *         (thanx to CrystalFontz for the sample devices - they flushed out
  *           some driver bugs)
  *      Minor debugging message changes
  *      Added throttle, unthrottle and chars_in_buffer functions
  *      Fixed FTDI_SIO (the original device) bug
  *      Fixed some shutdown handling
- *      
- * 
- * 
- * 
+ *
+ *
+ *
+ *
  * (07/Jun/2002) Kuba Ober
  *     Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
  *     function. It was getting too complex.
  *
  * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
  *      Not tested by me but it doesn't break anything I use.
- * 
+ *
  * (04/Jan/2002) Kuba Ober
  *     Implemented 38400 baudrate kludge, where it can be substituted with other
  *       values. That's the only way to set custom baudrates.
  *        (the previous version caused panics)
  *     Removed port iteration code since the device only has one I/O port and it
  *       was wrong anyway.
- * 
+ *
  * (31/May/2001) gkh
  *     Switched from using spinlock to a semaphore, which fixes lots of problems.
  *
  *     Cleaned up comments for 8U232
  *     Added parity, framing and overrun error handling
  *     Added receive break handling.
- * 
+ *
  * (04/08/2001) gb
  *     Identify version on module load.
- *       
+ *
  * (18/March/2001) Bill Ryder
  *     (Not released)
  *     Added send break handling. (requires kernel patch too)
  *     Fixed 8U232AM hardware RTS/CTS etc status reporting.
  *     Added flipbuf fix copied from generic device
- * 
+ *
  * (12/3/2000) Bill Ryder
  *     Added support for 8U232AM device.
  *     Moved PID and VIDs into header file only.
  *     Cleaned up comments. Removed multiple PID/VID definitions.
  *     Factorised cts/dtr code
  *     Made use of __FUNCTION__ in dbg's
- *      
+ *
  * (11/01/2000) Adam J. Richter
  *     usb_device_id table support
- * 
+ *
  * (10/05/2000) gkh
  *     Fixed bug with urb->dev not being set properly, now that the usb
  *     core needs it.
- * 
+ *
  * (09/11/2000) gkh
  *     Removed DEBUG #ifdefs with call to usb_serial_debug_data
  *
  *     Added module_init and module_exit functions to handle the fact that this
  *     driver is a loadable module now.
  *
- * (04/04/2000) Bill Ryder 
+ * (04/04/2000) Bill Ryder
  *     Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
  *        handled elsewhere in the tty io driver chain).
  *
- * (03/30/2000) Bill Ryder 
+ * (03/30/2000) Bill Ryder
  *     Implemented lots of ioctls
  *     Fixed a race condition in write
  *     Changed some dbg's to errs
@@ -444,13 +444,13 @@ static struct usb_device_id id_table_combined [] = {
        /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
        /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
        /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
-       { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
-       { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
-       { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
-       { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
-       { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
-       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
-       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
+       { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
+       { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
+       { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
+       { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
+       { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
        { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
        { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
        { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
@@ -522,7 +522,7 @@ static struct usb_driver ftdi_driver = {
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table_combined,
-       .no_dynamic_id =        1,
+       .no_dynamic_id =        1,
 };
 
 static const char *ftdi_chip_name[] = {
@@ -548,13 +548,13 @@ struct ftdi_private {
        int custom_divisor;     /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
        __u16 last_set_data_urb_value ;
                                /* the last data state set - needed for doing a break */
-        int write_offset;       /* This is the offset in the usb data block to write the serial data - 
+        int write_offset;       /* This is the offset in the usb data block to write the serial data -
                                 * it is different between devices
                                 */
        int flags;              /* some ASYNC_xxxx flags are supported */
        unsigned long last_dtr_rts;     /* saved modem control outputs */
         wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
-       char prev_status, diff_status;        /* Used for TIOCMIWAIT */
+       char prev_status, diff_status;        /* Used for TIOCMIWAIT */
        __u8 rx_flags;          /* receive state flags (throttling) */
        spinlock_t rx_lock;     /* spinlock for receive state */
        struct work_struct rx_work;
@@ -721,7 +721,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned
                urb_value |= FTDI_SIO_SET_RTS_HIGH;
        rv = usb_control_msg(port->serial->dev,
                               usb_sndctrlpipe(port->serial->dev, 0),
-                              FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+                              FTDI_SIO_SET_MODEM_CTRL_REQUEST,
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
                               urb_value, priv->interface,
                               buf, 0, WDR_TIMEOUT);
@@ -768,7 +768,7 @@ static int change_speed(struct usb_serial_port *port)
        if (priv->interface) {  /* FT2232C */
                urb_index = (__u16)((urb_index << 8) | priv->interface);
        }
-       
+
        rv = usb_control_msg(port->serial->dev,
                            usb_sndctrlpipe(port->serial->dev, 0),
                            FTDI_SIO_SET_BAUDRATE_REQUEST,
@@ -827,7 +827,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
 
        /* 3. Convert baudrate to device-specific divisor */
 
-       if (!baud) baud = 9600; 
+       if (!baud) baud = 9600;
        switch(priv->chip_type) {
        case SIO: /* SIO chip */
                switch(baud) {
@@ -843,7 +843,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
                case 115200: div_value = ftdi_sio_b115200; break;
                } /* baud */
                if (div_value == 0) {
-                       dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__,  baud);
+                       dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__,  baud);
                        div_value = ftdi_sio_b9600;
                        div_okay = 0;
                }
@@ -925,7 +925,7 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _
        /* Make the changes - these are privileged changes! */
 
        priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
-                      (new_serial.flags & ASYNC_FLAGS));       
+                      (new_serial.flags & ASYNC_FLAGS));
        priv->custom_divisor = new_serial.custom_divisor;
 
        port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
@@ -950,7 +950,7 @@ check_and_exit:
             (old_priv.custom_divisor != priv->custom_divisor))) {
                change_speed(port);
        }
-       
+
        return (0);
 
 } /* set_serial_info */
@@ -1022,18 +1022,18 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a
        struct usb_device *udev;
        unsigned short latency = 0;
        int rv = 0;
-       
+
        udev = to_usb_device(dev);
-       
+
        dbg("%s",__FUNCTION__);
-       
+
        rv = usb_control_msg(udev,
                             usb_rcvctrlpipe(udev, 0),
                             FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
                             FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
-                            0, priv->interface, 
+                            0, priv->interface,
                             (char*) &latency, 1, WDR_TIMEOUT);
-       
+
        if (rv < 0) {
                dev_err(dev, "Unable to read latency timer: %i", rv);
                return -EIO;
@@ -1051,23 +1051,23 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute *
        char buf[1];
        int v = simple_strtoul(valbuf, NULL, 10);
        int rv = 0;
-       
+
        udev = to_usb_device(dev);
-       
+
        dbg("%s: setting latency timer = %i", __FUNCTION__, v);
-       
+
        rv = usb_control_msg(udev,
                             usb_sndctrlpipe(udev, 0),
                             FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
                             FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
-                            v, priv->interface, 
+                            v, priv->interface,
                             buf, 0, WDR_TIMEOUT);
-       
+
        if (rv < 0) {
                dev_err(dev, "Unable to write latency timer: %i", rv);
                return -EIO;
        }
-       
+
        return count;
 }
 
@@ -1082,23 +1082,23 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
        char buf[1];
        int v = simple_strtoul(valbuf, NULL, 10);
        int rv = 0;
-       
+
        udev = to_usb_device(dev);
-       
+
        dbg("%s: setting event char = %i", __FUNCTION__, v);
-       
+
        rv = usb_control_msg(udev,
                             usb_sndctrlpipe(udev, 0),
                             FTDI_SIO_SET_EVENT_CHAR_REQUEST,
                             FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
-                            v, priv->interface, 
+                            v, priv->interface,
                             buf, 0, WDR_TIMEOUT);
-       
+
        if (rv < 0) {
                dbg("Unable to write event character: %i", rv);
                return -EIO;
        }
-       
+
        return count;
 }
 
@@ -1135,11 +1135,11 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
        struct ftdi_private *priv;
        struct usb_device *udev;
 
-       dbg("%s",__FUNCTION__); 
+       dbg("%s",__FUNCTION__);
 
        priv = usb_get_serial_port_data(serial->port[0]);
        udev = serial->dev;
-       
+
        /* XXX see create_sysfs_attrs */
        if (priv->chip_type != SIO) {
                device_remove_file(&udev->dev, &dev_attr_event_char);
@@ -1147,7 +1147,7 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
                        device_remove_file(&udev->dev, &dev_attr_latency_timer);
                }
        }
-       
+
 }
 
 /*
@@ -1258,7 +1258,7 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
 } /* ftdi_HE_TIRA1_setup */
 
 
-/* ftdi_shutdown is called from usbserial:usb_serial_disconnect 
+/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
  *   it is called when the usb device is disconnected
  *
  *   usbserial:usb_serial_disconnect
@@ -1269,16 +1269,16 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
 
 static void ftdi_shutdown (struct usb_serial *serial)
 { /* ftdi_shutdown */
-       
+
        struct usb_serial_port *port = serial->port[0];
        struct ftdi_private *priv = usb_get_serial_port_data(port);
 
        dbg("%s", __FUNCTION__);
 
        remove_sysfs_attrs(serial);
-       
-       /* all open ports are closed at this point 
-         *    (by usbserial.c:__serial_close, which calls ftdi_close)  
+
+       /* all open ports are closed at this point
+         *    (by usbserial.c:__serial_close, which calls ftdi_close)
         */
 
        if (priv) {
@@ -1293,7 +1293,7 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
        struct usb_device *dev = port->serial->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
-       
+
        int result = 0;
        char buf[1]; /* Needed for the usb_control_msg I think */
 
@@ -1312,8 +1312,8 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
        /* No error checking for this (will get errors later anyway) */
        /* See ftdi_sio.h for description of what is reset */
        usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                       FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
-                       FTDI_SIO_RESET_SIO, 
+                       FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+                       FTDI_SIO_RESET_SIO,
                        priv->interface, buf, 0, WDR_TIMEOUT);
 
        /* Termios defaults are set by usb_serial_init. We don't change
@@ -1350,12 +1350,12 @@ static int  ftdi_open (struct usb_serial_port *port, struct file *filp)
 
 
 
-/* 
+/*
  * usbserial:__serial_close  only calls ftdi_close if the point is open
  *
  *   This only gets called when it is the last close
- *   
- *   
+ *
+ *
  */
 
 static void ftdi_close (struct usb_serial_port *port, struct file *filp)
@@ -1368,14 +1368,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
 
        if (c_cflag & HUPCL){
                /* Disable flow control */
-               if (usb_control_msg(port->serial->dev, 
+               if (usb_control_msg(port->serial->dev,
                                    usb_sndctrlpipe(port->serial->dev, 0),
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                    0, priv->interface, buf, 0,
                                    WDR_TIMEOUT) < 0) {
                        err("error from flowcontrol urb");
-               }           
+               }
 
                /* drop RTS and DTR */
                clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
@@ -1384,14 +1384,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
        /* cancel any scheduled reading */
        cancel_delayed_work(&priv->rx_work);
        flush_scheduled_work();
-       
+
        /* shutdown our bulk read */
        if (port->read_urb)
                usb_kill_urb(port->read_urb);
 } /* ftdi_close */
 
 
-  
+
 /* The SIO requires the first byte to have:
  *  B0 1
  *  B1 0
@@ -1423,7 +1423,7 @@ static int ftdi_write (struct usb_serial_port *port,
                return 0;
        }
        spin_unlock_irqrestore(&priv->tx_lock, flags);
-       
+
        data_offset = priv->write_offset;
         dbg("data_offset set to %d",data_offset);
 
@@ -1462,7 +1462,7 @@ static int ftdi_write (struct usb_serial_port *port,
                                user_pktsz = todo;
                        }
                        /* Write the control byte at the front of the packet*/
-                       *first_byte = 1 | ((user_pktsz) << 2); 
+                       *first_byte = 1 | ((user_pktsz) << 2);
                        /* Copy data for packet */
                        memcpy (first_byte + data_offset,
                                current_position, user_pktsz);
@@ -1479,7 +1479,7 @@ static int ftdi_write (struct usb_serial_port *port,
        usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer);
 
        /* fill the buffer and send it */
-       usb_fill_bulk_urb(urb, port->serial->dev, 
+       usb_fill_bulk_urb(urb, port->serial->dev,
                      usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
                      buffer, transfer_size,
                      ftdi_write_bulk_callback, port);
@@ -1520,7 +1520,7 @@ static void ftdi_write_bulk_callback (struct urb *urb)
        kfree (urb->transfer_buffer);
 
        dbg("%s - port %d", __FUNCTION__, port->number);
-       
+
        if (urb->status) {
                dbg("nonzero write bulk status received: %d", urb->status);
                return;
@@ -1651,7 +1651,7 @@ static void ftdi_process_read (void *param)
        struct tty_struct *tty;
        struct ftdi_private *priv;
        char error_flag;
-               unsigned char *data;
+       unsigned char *data;
 
        int i;
        int result;
@@ -1759,7 +1759,7 @@ static void ftdi_process_read (void *param)
                }
                if (length > 0) {
                        for (i = 2; i < length+2; i++) {
-                               /* Note that the error flag is duplicated for 
+                               /* Note that the error flag is duplicated for
                                   every character received since we don't know
                                   which character it applied to */
                                tty_insert_flip_char(tty, data[packet_offset+i], error_flag);
@@ -1773,7 +1773,7 @@ static void ftdi_process_read (void *param)
                   This doesn't work well since the application receives a never
                   ending stream of bad data - even though new data hasn't been sent.
                   Therefore I (bill) have taken this out.
-                  However - this might make sense for framing errors and so on 
+                  However - this might make sense for framing errors and so on
                   so I am leaving the code in for now.
                */
                else {
@@ -1827,7 +1827,7 @@ static void ftdi_process_read (void *param)
        /* if the port is closed stop trying to read */
        if (port->open_count > 0){
                /* Continue trying to always read  */
-               usb_fill_bulk_urb(port->read_urb, port->serial->dev, 
+               usb_fill_bulk_urb(port->read_urb, port->serial->dev,
                              usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress),
                              port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
                              ftdi_read_bulk_callback, port);
@@ -1844,9 +1844,9 @@ static void ftdi_process_read (void *param)
 static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       __u16 urb_value = 0; 
+       __u16 urb_value = 0;
        char buf[1];
-       
+
        /* break_state = -1 to turn on break, and 0 to turn off break */
        /* see drivers/char/tty_io.c to see it used */
        /* last_set_data_urb_value NEVER has the break bit set in it */
@@ -1854,20 +1854,20 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
        if (break_state) {
                urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK;
        } else {
-               urb_value = priv->last_set_data_urb_value; 
+               urb_value = priv->last_set_data_urb_value;
        }
 
-       
+
        if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
-                           FTDI_SIO_SET_DATA_REQUEST, 
+                           FTDI_SIO_SET_DATA_REQUEST,
                            FTDI_SIO_SET_DATA_REQUEST_TYPE,
                            urb_value , priv->interface,
                            buf, 0, WDR_TIMEOUT) < 0) {
                err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
-       }          
+       }
 
        dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);
-       
+
 }
 
 
@@ -1883,12 +1883,12 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        __u16 urb_value; /* will hold the new flags */
        char buf[1]; /* Perhaps I should dynamically alloc this? */
-       
+
        // Added for xon/xoff support
        unsigned int iflag = port->tty->termios->c_iflag;
        unsigned char vstop;
        unsigned char vstart;
-       
+
        dbg("%s", __FUNCTION__);
 
        /* Force baud rate if this device requires it, unless it is set to B0. */
@@ -1906,20 +1906,20 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
 
        cflag = port->tty->termios->c_cflag;
 
-       /* FIXME -For this cut I don't care if the line is really changing or 
-          not  - so just do the change regardless  - should be able to 
+       /* FIXME -For this cut I don't care if the line is really changing or
+          not  - so just do the change regardless  - should be able to
           compare old_termios and tty->termios */
-       /* NOTE These routines can get interrupted by 
-          ftdi_sio_read_bulk_callback  - need to examine what this 
+       /* NOTE These routines can get interrupted by
+          ftdi_sio_read_bulk_callback  - need to examine what this
            means - don't see any problems yet */
-       
+
        /* Set number of data bits, parity, stop bits */
-       
+
        urb_value = 0;
        urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
                      FTDI_SIO_SET_DATA_STOP_BITS_1);
-       urb_value |= (cflag & PARENB ? 
-                     (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : 
+       urb_value |= (cflag & PARENB ?
+                     (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
                       FTDI_SIO_SET_DATA_PARITY_EVEN) :
                      FTDI_SIO_SET_DATA_PARITY_NONE);
        if (cflag & CSIZE) {
@@ -1936,25 +1936,25 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
        /* This is needed by the break command since it uses the same command - but is
         *  or'ed with this value  */
        priv->last_set_data_urb_value = urb_value;
-       
+
        if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                           FTDI_SIO_SET_DATA_REQUEST, 
+                           FTDI_SIO_SET_DATA_REQUEST,
                            FTDI_SIO_SET_DATA_REQUEST_TYPE,
                            urb_value , priv->interface,
                            buf, 0, WDR_SHORT_TIMEOUT) < 0) {
                err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
-       }          
+       }
 
        /* Now do the baudrate */
        if ((cflag & CBAUD) == B0 ) {
                /* Disable flow control */
                if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                                   0, priv->interface, 
+                                   0, priv->interface,
                                    buf, 0, WDR_TIMEOUT) < 0) {
                        err("%s error from disable flowcontrol urb", __FUNCTION__);
-               }           
+               }
                /* Drop RTS and DTR */
                clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
        } else {
@@ -1972,16 +1972,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
        /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
        if (cflag & CRTSCTS) {
                dbg("%s Setting to CRTSCTS flow control", __FUNCTION__);
-               if (usb_control_msg(dev, 
+               if (usb_control_msg(dev,
                                    usb_sndctrlpipe(dev, 0),
-                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                    0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
                                    buf, 0, WDR_TIMEOUT) < 0) {
                        err("urb failed to set to rts/cts flow control");
-               }               
-               
-       } else { 
+               }
+
+       } else {
                /*
                 * Xon/Xoff code
                 *
@@ -2011,16 +2011,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
                        /* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */
                        /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */
                        dbg("%s Turning off hardware flow control", __FUNCTION__);
-                       if (usb_control_msg(dev, 
+                       if (usb_control_msg(dev,
                                            usb_sndctrlpipe(dev, 0),
-                                           FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+                                           FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                            FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                                           0, priv->interface, 
+                                           0, priv->interface,
                                            buf, 0, WDR_TIMEOUT) < 0) {
                                err("urb failed to clear flow control");
-                       }                               
+                       }
                }
-               
+
        }
        return;
 } /* ftdi_termios */
@@ -2036,11 +2036,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
        switch (priv->chip_type) {
        case SIO:
                /* Request the status from the device */
-               if ((ret = usb_control_msg(port->serial->dev, 
+               if ((ret = usb_control_msg(port->serial->dev,
                                           usb_rcvctrlpipe(port->serial->dev, 0),
-                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
+                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST,
                                           FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-                                          0, 0, 
+                                          0, 0,
                                           buf, 1, WDR_TIMEOUT)) < 0 ) {
                        err("%s Could not get modem status of device - err: %d", __FUNCTION__,
                            ret);
@@ -2052,11 +2052,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
        case FT2232C:
                /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
                   format as the data returned from the in point */
-               if ((ret = usb_control_msg(port->serial->dev, 
+               if ((ret = usb_control_msg(port->serial->dev,
                                           usb_rcvctrlpipe(port->serial->dev, 0),
-                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
+                                          FTDI_SIO_GET_MODEM_STATUS_REQUEST,
                                           FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-                                          0, priv->interface, 
+                                          0, priv->interface,
                                           buf, 2, WDR_TIMEOUT)) < 0 ) {
                        err("%s Could not get modem status of device - err: %d", __FUNCTION__,
                            ret);
@@ -2067,12 +2067,12 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
                return -EFAULT;
                break;
        }
-       
+
        return  (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
                (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
                (buf[0]  & FTDI_SIO_RI_MASK  ? TIOCM_RI  : 0) |
                (buf[0]  & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0) |
-               priv->last_dtr_rts;                     
+               priv->last_dtr_rts;
 }
 
 static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
@@ -2138,11 +2138,11 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
                break;
        default:
                break;
-               
+
        }
 
 
-       /* This is not necessarily an error - turns out the higher layers will do 
+       /* This is not necessarily an error - turns out the higher layers will do
         *  some ioctls itself (see comment above)
         */
        dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
@@ -2199,7 +2199,7 @@ static int __init ftdi_init (void)
        if (retval)
                goto failed_sio_register;
        retval = usb_register(&ftdi_driver);
-       if (retval) 
+       if (retval)
                goto failed_usb_register;
 
        info(DRIVER_VERSION ":" DRIVER_DESC);
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
new file mode 100644 (file)
index 0000000..82cd15b
--- /dev/null
@@ -0,0 +1,1683 @@
+/*
+ * mos7720.c
+ *   Controls the Moschip 7720 usb to dual port serial convertor
+ *
+ * Copyright 2006 Moschip Semiconductor Tech. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * Developed by:
+ *     VijayaKumar.G.N. <vijaykumar@aspirecom.net>
+ *     AjayKumar <ajay@aspirecom.net>
+ *     Gurudeva.N. <gurudev@aspirecom.net>
+ *
+ * Cleaned up from the original by:
+ *     Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * Originally based on drivers/usb/serial/io_edgeport.c which is:
+ *     Copyright (C) 2000 Inside Out Networks, All rights reserved.
+ *     Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <asm/uaccess.h>
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.0.0.4F"
+#define DRIVER_AUTHOR "Aspire Communications pvt Ltd."
+#define DRIVER_DESC "Moschip USB Serial Driver"
+
+/* default urb timeout */
+#define MOS_WDR_TIMEOUT        (HZ * 5)
+
+#define MOS_PORT1      0x0200
+#define MOS_PORT2      0x0300
+#define MOS_VENREG     0x0000
+#define MOS_MAX_PORT   0x02
+#define MOS_WRITE      0x0E
+#define MOS_READ       0x0D
+
+/* Interrupt Rotinue Defines   */
+#define SERIAL_IIR_RLS 0x06
+#define SERIAL_IIR_RDA 0x04
+#define SERIAL_IIR_CTI 0x0c
+#define SERIAL_IIR_THR 0x02
+#define SERIAL_IIR_MS  0x00
+
+#define NUM_URBS                       16      /* URB Count */
+#define URB_TRANSFER_BUFFER_SIZE       32      /* URB Size */
+
+/* This structure holds all of the local port information */
+struct moschip_port
+{
+       __u8    shadowLCR;              /* last LCR value received */
+       __u8    shadowMCR;              /* last MCR value received */
+       __u8    shadowMSR;              /* last MSR value received */
+       char                    open;
+       struct async_icount     icount;
+       struct usb_serial_port  *port;  /* loop back to the owner */
+       struct urb              *write_urb_pool[NUM_URBS];
+};
+
+/* This structure holds all of the individual serial device information */
+struct moschip_serial
+{
+       int interrupt_started;
+};
+
+static int debug;
+
+#define USB_VENDOR_ID_MOSCHIP          0x9710
+#define MOSCHIP_DEVICE_ID_7720         0x7720
+#define MOSCHIP_DEVICE_ID_7715         0x7715
+
+static struct usb_device_id moschip_port_id_table [] = {
+       { USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) },
+       { } /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, moschip_port_id_table);
+
+
+/*
+ * mos7720_interrupt_callback
+ *     this is the callback function for when we have received data on the
+ *     interrupt endpoint.
+ */
+static void mos7720_interrupt_callback(struct urb *urb)
+{
+       int result;
+       int length;
+       __u32 *data;
+       unsigned int status;
+       __u8 sp1;
+       __u8 sp2;
+       __u8 st;
+
+       dbg("%s"," : Entering\n");
+
+       if (!urb) {
+               dbg("%s","Invalid Pointer !!!!:\n");
+               return;
+       }
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+                   urb->status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+                   urb->status);
+               goto exit;
+       }
+
+       length = urb->actual_length;
+       data = urb->transfer_buffer;
+
+       /* Moschip get 4 bytes
+        * Byte 1 IIR Port 1 (port.number is 0)
+        * Byte 2 IIR Port 2 (port.number is 1)
+        * Byte 3 --------------
+        * Byte 4 FIFO status for both */
+       if (length && length > 4) {
+               dbg("Wrong data !!!");
+               return;
+       }
+
+       status = *data;
+
+       sp1 = (status & 0xff000000)>>24;
+       sp2 = (status & 0x00ff0000)>>16;
+       st = status & 0x000000ff;
+
+       if ((sp1 & 0x01) || (sp2 & 0x01)) {
+               /* No Interrupt Pending in both the ports */
+               dbg("No Interrupt !!!");
+       } else {
+               switch (sp1 & 0x0f) {
+               case SERIAL_IIR_RLS:
+                       dbg("Serial Port 1: Receiver status error or address "
+                           "bit detected in 9-bit mode\n");
+                       break;
+               case SERIAL_IIR_CTI:
+                       dbg("Serial Port 1: Receiver time out");
+                       break;
+               case SERIAL_IIR_MS:
+                       dbg("Serial Port 1: Modem status change");
+                       break;
+               }
+
+               switch (sp2 & 0x0f) {
+               case SERIAL_IIR_RLS:
+                       dbg("Serial Port 2: Receiver status error or address "
+                           "bit detected in 9-bit mode");
+                       break;
+               case SERIAL_IIR_CTI:
+                       dbg("Serial Port 2: Receiver time out");
+                       break;
+               case SERIAL_IIR_MS:
+                       dbg("Serial Port 2: Modem status change");
+                       break;
+               }
+       }
+
+exit:
+       result = usb_submit_urb(urb, GFP_ATOMIC);
+       if (result)
+               dev_err(&urb->dev->dev,
+                       "%s - Error %d submitting control urb\n",
+                       __FUNCTION__, result);
+       return;
+}
+
+/*
+ * mos7720_bulk_in_callback
+ *     this is the callback function for when we have received data on the
+ *     bulk in endpoint.
+ */
+static void mos7720_bulk_in_callback(struct urb *urb)
+{
+       int status;
+       unsigned char *data ;
+       struct usb_serial_port *port;
+       struct moschip_port *mos7720_port;
+       struct tty_struct *tty;
+
+       if (urb->status) {
+               dbg("nonzero read bulk status received: %d",urb->status);
+               return;
+       }
+
+       mos7720_port = urb->context;
+       if (!mos7720_port) {
+               dbg("%s","NULL mos7720_port pointer \n");
+               return ;
+       }
+
+       port = mos7720_port->port;
+
+       dbg("Entering...%s", __FUNCTION__);
+
+       data = urb->transfer_buffer;
+
+       tty = port->tty;
+       if (tty && urb->actual_length) {
+               tty_buffer_request_room(tty, urb->actual_length);
+               tty_insert_flip_string(tty, data, urb->actual_length);
+               tty_flip_buffer_push(tty);
+       }
+
+       if (!port->read_urb) {
+               dbg("URB KILLED !!!");
+               return;
+       }
+
+       if (port->read_urb->status != -EINPROGRESS) {
+               port->read_urb->dev = port->serial->dev;
+
+               status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+               if (status)
+                       dbg("usb_submit_urb(read bulk) failed, status = %d",
+                           status);
+       }
+}
+
+/*
+ * mos7720_bulk_out_data_callback
+ *     this is the callback function for when we have finished sending serial
+ *     data on the bulk out endpoint.
+ */
+static void mos7720_bulk_out_data_callback(struct urb *urb)
+{
+       struct moschip_port *mos7720_port;
+       struct tty_struct *tty;
+
+       if (urb->status) {
+               dbg("nonzero write bulk status received:%d", urb->status);
+               return;
+       }
+
+       mos7720_port = urb->context;
+       if (!mos7720_port) {
+               dbg("NULL mos7720_port pointer");
+               return ;
+       }
+
+       dbg("Entering .........");
+
+       tty = mos7720_port->port->tty;
+
+       if (tty && mos7720_port->open) {
+               /* let the tty driver wakeup if it has a special *
+                * write_wakeup function */
+               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                    tty->ldisc.write_wakeup)
+                       (tty->ldisc.write_wakeup)(tty);
+
+               /* tell the tty driver that something has changed */
+               wake_up_interruptible(&tty->write_wait);
+       }
+
+       /* schedule_work(&mos7720_port->port->work); */
+}
+
+/*
+ * send_mos_cmd
+ *     this function will be used for sending command to device
+ */
+static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
+                       __u16 index, void *data)
+{
+       int status;
+       unsigned int pipe;
+       u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+       __u8 requesttype;
+       __u16 size = 0x0000;
+
+       if (value < MOS_MAX_PORT) {
+               if (product == MOSCHIP_DEVICE_ID_7715) {
+                       value = value*0x100+0x100;
+               } else {
+                       value = value*0x100+0x200;
+               }
+       } else {
+               value = 0x0000;
+               if ((product == MOSCHIP_DEVICE_ID_7715) &&
+                   (index != 0x08)) {
+                       dbg("serial->product== MOSCHIP_DEVICE_ID_7715");
+                       //index = 0x01 ;
+               }
+       }
+
+       if (request == MOS_WRITE) {
+               request = (__u8)MOS_WRITE;
+               requesttype = (__u8)0x40;
+               value  = value + (__u16)*((unsigned char *)data);
+               data = NULL;
+               pipe = usb_sndctrlpipe(serial->dev, 0);
+       } else {
+               request = (__u8)MOS_READ;
+               requesttype = (__u8)0xC0;
+               size = 0x01;
+               pipe = usb_rcvctrlpipe(serial->dev,0);
+       }
+
+       status = usb_control_msg(serial->dev, pipe, request, requesttype,
+                                value, index, data, size, MOS_WDR_TIMEOUT);
+
+       if (status < 0)
+               dbg("Command Write failed Value %x index %x\n",value,index);
+
+       return status;
+}
+
+static int mos7720_open(struct usb_serial_port *port, struct file * filp)
+{
+       struct usb_serial *serial;
+       struct usb_serial_port *port0;
+       struct urb *urb;
+       struct moschip_serial *mos7720_serial;
+       struct moschip_port *mos7720_port;
+       int response;
+       int port_number;
+       char data;
+       int j;
+
+       serial = port->serial;
+
+       mos7720_port = usb_get_serial_port_data(port);
+       if (mos7720_port == NULL)
+               return -ENODEV;
+
+       port0 = serial->port[0];
+
+       mos7720_serial = usb_get_serial_data(serial);
+
+       if (mos7720_serial == NULL || port0 == NULL)
+               return -ENODEV;
+
+       usb_clear_halt(serial->dev, port->write_urb->pipe);
+       usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+       /* Initialising the write urb pool */
+       for (j = 0; j < NUM_URBS; ++j) {
+               urb = usb_alloc_urb(0,SLAB_ATOMIC);
+               mos7720_port->write_urb_pool[j] = urb;
+
+               if (urb == NULL) {
+                       err("No more urbs???");
+                       continue;
+               }
+
+               urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
+                                              GFP_KERNEL);
+               if (!urb->transfer_buffer) {
+                       err("%s-out of memory for urb buffers.", __FUNCTION__);
+                       continue;
+               }
+       }
+
+        /* Initialize MCS7720 -- Write Init values to corresponding Registers
+         *
+         * Register Index
+         * 1 : IER
+         * 2 : FCR
+         * 3 : LCR
+         * 4 : MCR
+         *
+         * 0x08 : SP1/2 Control Reg
+         */
+       port_number = port->number - port->serial->minor;
+       send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data);
+       dbg("SS::%p LSR:%x\n",mos7720_port, data);
+
+       dbg("Check:Sending Command ..........");
+
+       data = 0x02;
+       send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data);
+       data = 0x02;
+       send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data);
+
+       data = 0x00;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+       data = 0x00;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
+
+       data = 0xCF;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
+       data = 0x03;
+        mos7720_port->shadowLCR  = data;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+       data = 0x0b;
+        mos7720_port->shadowMCR  = data;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+       data = 0x0b;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+       data = 0x00;
+       send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+       data = 0x00;
+       send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+/*     data = 0x00;
+       send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data);
+       data = 0x03;
+       send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
+       data = 0x00;
+       send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
+*/
+       data = 0x00;
+       send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+
+       data = data | (port->number - port->serial->minor + 1);
+       send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+       data = 0x83;
+        mos7720_port->shadowLCR  = data;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+       data = 0x0c;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
+       data = 0x00;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+       data = 0x03;
+        mos7720_port->shadowLCR  = data;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+       data = 0x0c;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+       data = 0x0c;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+
+//Matrix
+
+       /* force low_latency on so that our tty_push actually forces *
+        * the data through,otherwise it is scheduled, and with      *
+        * high data rates (like with OHCI) data can get lost.       */
+
+       if (port->tty)
+               port->tty->low_latency = 1;
+
+       /* see if we've set up our endpoint info yet   *
+        * (can't set it up in mos7720_startup as the  *
+        * structures were not set up at that time.)   */
+       if (!mos7720_serial->interrupt_started) {
+               dbg("Interrupt buffer NULL !!!");
+
+               /* not set up yet, so do it now */
+               mos7720_serial->interrupt_started = 1;
+
+               dbg("To Submit URB !!!");
+
+               /* set up our interrupt urb */
+               usb_fill_int_urb(port0->interrupt_in_urb, serial->dev,
+                                usb_rcvintpipe(serial->dev,
+                                               port->interrupt_in_endpointAddress),
+                                port0->interrupt_in_buffer,
+                                port0->interrupt_in_urb->transfer_buffer_length,
+                                mos7720_interrupt_callback, mos7720_port,
+                                port0->interrupt_in_urb->interval);
+
+               /* start interrupt read for this mos7720 this interrupt *
+                * will continue as long as the mos7720 is connected    */
+               dbg("Submit URB over !!!");
+               response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL);
+               if (response)
+                       dev_err(&port->dev,
+                               "%s - Error %d submitting control urb",
+                               __FUNCTION__, response);
+       }
+
+       /* set up our bulk in urb */
+       usb_fill_bulk_urb(port->read_urb, serial->dev,
+                         usb_rcvbulkpipe(serial->dev,
+                                         port->bulk_in_endpointAddress),
+                         port->bulk_in_buffer,
+                         port->read_urb->transfer_buffer_length,
+                         mos7720_bulk_in_callback, mos7720_port);
+       response = usb_submit_urb(port->read_urb, GFP_KERNEL);
+       if (response)
+               dev_err(&port->dev,
+                       "%s - Error %d submitting read urb", __FUNCTION__, response);
+
+       /* initialize our icount structure */
+       memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
+
+       /* initialize our port settings */
+       mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */
+
+       /* send a open port command */
+       mos7720_port->open = 1;
+
+       return 0;
+}
+
+/*
+ * mos7720_chars_in_buffer
+ *     this function is called by the tty driver when it wants to know how many
+ *     bytes of data we currently have outstanding in the port (data that has
+ *     been written, but hasn't made it out the port yet)
+ *     If successful, we return the number of bytes left to be written in the
+ *     system,
+ *     Otherwise we return a negative error number.
+ */
+static int mos7720_chars_in_buffer(struct usb_serial_port *port)
+{
+       int i;
+       int chars = 0;
+       struct moschip_port *mos7720_port;
+
+       dbg("%s:entering ...........", __FUNCTION__);
+
+       mos7720_port = usb_get_serial_port_data(port);
+       if (mos7720_port == NULL) {
+               dbg("%s:leaving ...........", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
+                       chars += URB_TRANSFER_BUFFER_SIZE;
+       }
+       dbg("%s - returns %d", __FUNCTION__, chars);
+       return chars;
+}
+
+static void mos7720_close(struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_serial *serial;
+       struct moschip_port *mos7720_port;
+       char data;
+       int j;
+
+       dbg("mos7720_close:entering...");
+
+       serial = port->serial;
+
+       mos7720_port = usb_get_serial_port_data(port);
+       if (mos7720_port == NULL)
+               return;
+
+       for (j = 0; j < NUM_URBS; ++j)
+               usb_kill_urb(mos7720_port->write_urb_pool[j]);
+
+       /* Freeing Write URBs */
+       for (j = 0; j < NUM_URBS; ++j) {
+               if (mos7720_port->write_urb_pool[j]) {
+                       kfree(mos7720_port->write_urb_pool[j]->transfer_buffer);
+                       usb_free_urb(mos7720_port->write_urb_pool[j]);
+               }
+       }
+
+       /* While closing port, shutdown all bulk read, write  *
+        * and interrupt read if they exists                  */
+       if (serial->dev) {
+               dbg("Shutdown bulk write");
+               usb_kill_urb(port->write_urb);
+               dbg("Shutdown bulk read");
+               usb_kill_urb(port->read_urb);
+       }
+
+       data = 0x00;
+       send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+                    0x04, &data);
+
+       data = 0x00;
+       send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+                    0x01, &data);
+
+       mos7720_port->open = 0;
+
+       dbg("Leaving %s", __FUNCTION__);
+}
+
+static void mos7720_break(struct usb_serial_port *port, int break_state)
+{
+        unsigned char data;
+       struct usb_serial *serial;
+       struct moschip_port *mos7720_port;
+
+       dbg("Entering %s", __FUNCTION__);
+
+       serial = port->serial;
+
+       mos7720_port = usb_get_serial_port_data(port);
+       if (mos7720_port == NULL)
+               return;
+
+       if (break_state == -1)
+               data = mos7720_port->shadowLCR | UART_LCR_SBC;
+       else
+               data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
+
+       mos7720_port->shadowLCR  = data;
+       send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+                    0x03, &data);
+
+       return;
+}
+
+/*
+ * mos7720_write_room
+ *     this function is called by the tty driver when it wants to know how many
+ *     bytes of data we can accept for a specific port.
+ *     If successful, we return the amount of room that we have for this port
+ *     Otherwise we return a negative error number.
+ */
+static int mos7720_write_room(struct usb_serial_port *port)
+{
+       struct moschip_port *mos7720_port;
+       int room = 0;
+       int i;
+
+       dbg("%s:entering ...........", __FUNCTION__);
+
+       mos7720_port = usb_get_serial_port_data(port);
+       if (mos7720_port == NULL) {
+               dbg("%s:leaving ...........", __FUNCTION__);
+               return -ENODEV;
+       }
+
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
+                       room += URB_TRANSFER_BUFFER_SIZE;
+       }
+
+       dbg("%s - returns %d", __FUNCTION__, room);
+       return room;
+}
+
+static int mos7720_write(struct usb_serial_port *port,
+                        const unsigned char *data, int count)
+{
+       int status;
+       int i;
+       int bytes_sent = 0;
+       int transfer_size;
+
+       struct moschip_port *mos7720_port;
+       struct usb_serial *serial;
+       struct urb    *urb;
+       const unsigned char *current_position = data;
+
+       dbg("%s:entering ...........", __FUNCTION__);
+
+       serial = port->serial;
+
+       mos7720_port = usb_get_serial_port_data(port);
+       if (mos7720_port == NULL) {
+               dbg("mos7720_port is NULL");
+               return -ENODEV;
+       }
+
+       /* try to find a free urb in the list */
+       urb = NULL;
+
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
+                       urb = mos7720_port->write_urb_pool[i];
+                       dbg("URB:%d",i);
+                       break;
+               }
+       }
+
+       if (urb == NULL) {
+               dbg("%s - no more free urbs", __FUNCTION__);
+               goto exit;
+       }
+
+       if (urb->transfer_buffer == NULL) {
+               urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
+                                              GFP_KERNEL);
+               if (urb->transfer_buffer == NULL) {
+                       err("%s no more kernel memory...", __FUNCTION__);
+                       goto exit;
+               }
+       }
+       transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
+
+       memcpy(urb->transfer_buffer, current_position, transfer_size);
+       usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size,
+                             urb->transfer_buffer);
+
+       /* fill urb with data and submit  */
+       usb_fill_bulk_urb(urb, serial->dev,
+                         usb_sndbulkpipe(serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         urb->transfer_buffer, transfer_size,
+                         mos7720_bulk_out_data_callback, mos7720_port);
+
+       /* send it down the pipe */
+       status = usb_submit_urb(urb,GFP_ATOMIC);
+       if (status) {
+               err("%s - usb_submit_urb(write bulk) failed with status = %d",
+                   __FUNCTION__, status);
+               bytes_sent = status;
+               goto exit;
+       }
+       bytes_sent = transfer_size;
+
+exit:
+       return bytes_sent;
+}
+
+static void mos7720_throttle(struct usb_serial_port *port)
+{
+       struct moschip_port *mos7720_port;
+       struct tty_struct *tty;
+       int status;
+
+       dbg("%s- port %d\n", __FUNCTION__, port->number);
+
+       mos7720_port = usb_get_serial_port_data(port);
+
+       if (mos7720_port == NULL)
+               return;
+
+       if (!mos7720_port->open) {
+               dbg("port not opened");
+               return;
+       }
+
+       dbg("%s: Entering ..........", __FUNCTION__);
+
+       tty = port->tty;
+       if (!tty) {
+               dbg("%s - no tty available", __FUNCTION__);
+               return;
+       }
+
+       /* if we are implementing XON/XOFF, send the stop character */
+       if (I_IXOFF(tty)) {
+               unsigned char stop_char = STOP_CHAR(tty);
+               status = mos7720_write(port, &stop_char, 1);
+               if (status <= 0)
+                       return;
+       }
+
+       /* if we are implementing RTS/CTS, toggle that line */
+       if (tty->termios->c_cflag & CRTSCTS) {
+               mos7720_port->shadowMCR &= ~UART_MCR_RTS;
+               status = send_mos_cmd(port->serial, MOS_WRITE,
+                                     port->number - port->serial->minor,
+                                     UART_MCR, &mos7720_port->shadowMCR);
+               if (status != 0)
+                       return;
+       }
+}
+
+static void mos7720_unthrottle(struct usb_serial_port *port)
+{
+       struct tty_struct *tty;
+       int status;
+       struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
+
+       if (mos7720_port == NULL)
+               return;
+
+       if (!mos7720_port->open) {
+               dbg("%s - port not opened", __FUNCTION__);
+               return;
+       }
+
+       dbg("%s: Entering ..........", __FUNCTION__);
+
+       tty = port->tty;
+       if (!tty) {
+               dbg("%s - no tty available", __FUNCTION__);
+               return;
+       }
+
+       /* if we are implementing XON/XOFF, send the start character */
+       if (I_IXOFF(tty)) {
+               unsigned char start_char = START_CHAR(tty);
+               status = mos7720_write(port, &start_char, 1);
+               if (status <= 0)
+                       return;
+       }
+
+       /* if we are implementing RTS/CTS, toggle that line */
+       if (tty->termios->c_cflag & CRTSCTS) {
+               mos7720_port->shadowMCR |= UART_MCR_RTS;
+               status = send_mos_cmd(port->serial, MOS_WRITE,
+                                     port->number - port->serial->minor,
+                                     UART_MCR, &mos7720_port->shadowMCR);
+               if (status != 0)
+                       return;
+       }
+}
+
+static int set_higher_rates(struct moschip_port *mos7720_port,
+                           unsigned int baud)
+{
+       unsigned char data;
+       struct usb_serial_port *port;
+       struct usb_serial *serial;
+       int port_number;
+
+       if (mos7720_port == NULL)
+               return -EINVAL;
+
+       port = mos7720_port->port;
+       serial = port->serial;
+
+        /***********************************************
+         *      Init Sequence for higher rates
+         ***********************************************/
+       dbg("Sending Setting Commands ..........");
+       port_number = port->number - port->serial->minor;
+
+       data = 0x000;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+       data = 0x000;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
+       data = 0x0CF;
+       send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data);
+       data = 0x00b;
+        mos7720_port->shadowMCR  = data;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+       data = 0x00b;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+       data = 0x000;
+       send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+       data = 0x000;
+       send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+
+        /***********************************************
+         *              Set for higher rates           *
+         ***********************************************/
+
+       data = baud * 0x10;
+       send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data);
+
+       data = 0x003;
+       send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+       data = 0x003;
+       send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+       data = 0x02b;
+        mos7720_port->shadowMCR  = data;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+       data = 0x02b;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+        /***********************************************
+         *              Set DLL/DLM
+         ***********************************************/
+
+       data = mos7720_port->shadowLCR | UART_LCR_DLAB;
+        mos7720_port->shadowLCR  = data;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+
+       data =  0x001; /* DLL */
+        send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
+       data =  0x000; /* DLM */
+        send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+
+       data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
+        mos7720_port->shadowLCR  = data;
+       send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+
+       return 0;
+}
+
+/* baud rate information */
+struct divisor_table_entry
+{
+       __u32  baudrate;
+       __u16  divisor;
+};
+
+/* Define table of divisors for moschip 7720 hardware     *
+ * These assume a 3.6864MHz crystal, the standard /16, and *
+ * MCR.7 = 0.                                             */
+static struct divisor_table_entry divisor_table[] = {
+       {   50,         2304},
+       {   110,        1047},  /* 2094.545455 => 230450   => .0217 % over */
+       {   134,        857},   /* 1713.011152 => 230398.5 => .00065% under */
+       {   150,        768},
+       {   300,        384},
+       {   600,        192},
+       {   1200,       96},
+       {   1800,       64},
+       {   2400,       48},
+       {   4800,       24},
+       {   7200,       16},
+       {   9600,       12},
+       {   19200,      6},
+       {   38400,      3},
+       {   57600,      2},
+       {   115200,     1},
+};
+
+/*****************************************************************************
+ * calc_baud_rate_divisor
+ *     this function calculates the proper baud rate divisor for the specified
+ *     baud rate.
+ *****************************************************************************/
+static int calc_baud_rate_divisor(int baudrate, int *divisor)
+{
+       int i;
+       __u16 custom;
+       __u16 round1;
+       __u16 round;
+
+
+       dbg("%s - %d", __FUNCTION__, baudrate);
+
+       for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
+               if (divisor_table[i].baudrate == baudrate) {
+                       *divisor = divisor_table[i].divisor;
+                       return 0;
+               }
+       }
+
+        /* After trying for all the standard baud rates    *
+         * Try calculating the divisor for this baud rate  */
+       if (baudrate > 75 &&  baudrate < 230400) {
+               /* get the divisor */
+               custom = (__u16)(230400L  / baudrate);
+
+               /* Check for round off */
+               round1 = (__u16)(2304000L / baudrate);
+               round = (__u16)(round1 - (custom * 10));
+               if (round > 4)
+                       custom++;
+               *divisor = custom;
+
+               dbg("Baud %d = %d",baudrate, custom);
+               return 0;
+       }
+
+       dbg("Baud calculation Failed...");
+       return -EINVAL;
+}
+
+/*
+ * send_cmd_write_baud_rate
+ *     this function sends the proper command to change the baud rate of the
+ *     specified port.
+ */
+static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
+                                   int baudrate)
+{
+       struct usb_serial_port *port;
+       struct usb_serial *serial;
+       int divisor;
+       int status;
+       unsigned char data;
+       unsigned char number;
+
+       if (mos7720_port == NULL)
+               return -1;
+
+       port = mos7720_port->port;
+       serial = port->serial;
+
+       dbg("%s: Entering ..........", __FUNCTION__);
+
+       number = port->number - port->serial->minor;
+       dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate);
+
+        /* Calculate the Divisor */
+       status = calc_baud_rate_divisor(baudrate, &divisor);
+       if (status) {
+               err("%s - bad baud rate", __FUNCTION__);
+               return status;
+       }
+
+        /* Enable access to divisor latch */
+        data = mos7720_port->shadowLCR | UART_LCR_DLAB;
+        mos7720_port->shadowLCR  = data;
+        send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data);
+
+       /* Write the divisor */
+       data = ((unsigned char)(divisor & 0xff));
+        send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data);
+
+       data = ((unsigned char)((divisor & 0xff00) >> 8));
+        send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data);
+
+        /* Disable access to divisor latch */
+        data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
+        mos7720_port->shadowLCR = data;
+        send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data);
+
+       return status;
+}
+
+/*
+ * change_port_settings
+ *     This routine is called to set the UART on the device to match
+ *      the specified new settings.
+ */
+static void change_port_settings(struct moschip_port *mos7720_port,
+                                struct termios *old_termios)
+{
+       struct usb_serial_port *port;
+       struct usb_serial *serial;
+       struct tty_struct *tty;
+       int baud;
+       unsigned cflag;
+       unsigned iflag;
+       __u8 mask = 0xff;
+       __u8 lData;
+       __u8 lParity;
+       __u8 lStop;
+       int status;
+       int port_number;
+       char data;
+
+       if (mos7720_port == NULL)
+               return ;
+
+       port = mos7720_port->port;
+       serial = port->serial;
+       port_number = port->number - port->serial->minor;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       if (!mos7720_port->open) {
+               dbg("%s - port not opened", __FUNCTION__);
+               return;
+       }
+
+       tty = mos7720_port->port->tty;
+
+       if ((!tty) || (!tty->termios)) {
+               dbg("%s - no tty structures", __FUNCTION__);
+               return;
+       }
+
+       dbg("%s: Entering ..........", __FUNCTION__);
+
+       lData = UART_LCR_WLEN8;
+       lStop = 0x00;   /* 1 stop bit */
+       lParity = 0x00; /* No parity */
+
+       cflag = tty->termios->c_cflag;
+       iflag = tty->termios->c_iflag;
+
+       /* Change the number of bits */
+       switch (cflag & CSIZE) {
+       case CS5:
+               lData = UART_LCR_WLEN5;
+               mask = 0x1f;
+               break;
+
+       case CS6:
+               lData = UART_LCR_WLEN6;
+               mask = 0x3f;
+               break;
+
+       case CS7:
+               lData = UART_LCR_WLEN7;
+               mask = 0x7f;
+               break;
+       default:
+       case CS8:
+               lData = UART_LCR_WLEN8;
+               break;
+       }
+
+       /* Change the Parity bit */
+       if (cflag & PARENB) {
+               if (cflag & PARODD) {
+                       lParity = UART_LCR_PARITY;
+                       dbg("%s - parity = odd", __FUNCTION__);
+               } else {
+                       lParity = (UART_LCR_EPAR | UART_LCR_PARITY);
+                       dbg("%s - parity = even", __FUNCTION__);
+               }
+
+       } else {
+               dbg("%s - parity = none", __FUNCTION__);
+       }
+
+       if (cflag & CMSPAR)
+               lParity = lParity | 0x20;
+
+       /* Change the Stop bit */
+       if (cflag & CSTOPB) {
+               lStop = UART_LCR_STOP;
+               dbg("%s - stop bits = 2", __FUNCTION__);
+       } else {
+               lStop = 0x00;
+               dbg("%s - stop bits = 1", __FUNCTION__);
+       }
+
+#define LCR_BITS_MASK          0x03    /* Mask for bits/char field */
+#define LCR_STOP_MASK          0x04    /* Mask for stop bits field */
+#define LCR_PAR_MASK           0x38    /* Mask for parity field */
+
+       /* Update the LCR with the correct value */
+       mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
+       mos7720_port->shadowLCR |= (lData | lParity | lStop);
+
+
+       /* Disable Interrupts */
+       data = 0x00;
+        send_mos_cmd(serial,MOS_WRITE,port->number - port->serial->minor, UART_IER, &data);
+
+       data = 0x00;
+        send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
+
+       data = 0xcf;
+        send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
+
+       /* Send the updated LCR value to the mos7720 */
+       data = mos7720_port->shadowLCR;
+        send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data);
+
+        data = 0x00b;
+        mos7720_port->shadowMCR = data;
+        send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+        data = 0x00b;
+        send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+       /* set up the MCR register and send it to the mos7720 */
+       mos7720_port->shadowMCR = UART_MCR_OUT2;
+       if (cflag & CBAUD)
+               mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS);
+
+       if (cflag & CRTSCTS) {
+               mos7720_port->shadowMCR |= (UART_MCR_XONANY);
+
+                /* To set hardware flow control to the specified *
+                 * serial port, in SP1/2_CONTROL_REG             */
+               if (port->number) {
+                       data = 0x001;
+                       send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
+                                    0x08, &data);
+               } else {
+                       data = 0x002;
+                       send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
+                                    0x08, &data);
+               }
+       } else {
+               mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
+       }
+
+       data = mos7720_port->shadowMCR;
+       send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data);
+
+       /* Determine divisor based on baud rate */
+       baud = tty_get_baud_rate(tty);
+       if (!baud) {
+               /* pick a default, any default... */
+               dbg("Picked default baud...");
+               baud = 9600;
+       }
+
+       if (baud >= 230400) {
+               set_higher_rates(mos7720_port, baud);
+               /* Enable Interrupts */
+               data = 0x0c;
+               send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
+               return;
+       }
+
+       dbg("%s - baud rate = %d", __FUNCTION__, baud);
+       status = send_cmd_write_baud_rate(mos7720_port, baud);
+
+       /* Enable Interrupts */
+       data = 0x0c;
+       send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
+
+       if (port->read_urb->status != -EINPROGRESS) {
+               port->read_urb->dev = serial->dev;
+
+               status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+               if (status)
+                       dbg("usb_submit_urb(read bulk) failed, status = %d",
+                           status);
+       }
+       return;
+}
+
+/*
+ * mos7720_set_termios
+ *     this function is called by the tty driver when it wants to change the
+ *     termios structure.
+ */
+static void mos7720_set_termios(struct usb_serial_port *port,
+                               struct termios *old_termios)
+{
+       int status;
+       unsigned int cflag;
+       struct usb_serial *serial;
+       struct moschip_port *mos7720_port;
+       struct tty_struct *tty;
+
+       serial = port->serial;
+
+       mos7720_port = usb_get_serial_port_data(port);
+
+       if (mos7720_port == NULL)
+               return;
+
+       tty = port->tty;
+
+       if (!port->tty || !port->tty->termios) {
+               dbg("%s - no tty or termios", __FUNCTION__);
+               return;
+       }
+
+       if (!mos7720_port->open) {
+               dbg("%s - port not opened", __FUNCTION__);
+               return;
+       }
+
+       dbg("%s\n","setting termios - ASPIRE");
+
+       cflag = tty->termios->c_cflag;
+
+       if (!cflag) {
+               printk("%s %s\n",__FUNCTION__,"cflag is NULL");
+               return;
+       }
+
+       /* check that they really want us to change something */
+       if (old_termios) {
+               if ((cflag == old_termios->c_cflag) &&
+                   (RELEVANT_IFLAG(tty->termios->c_iflag) ==
+                    RELEVANT_IFLAG(old_termios->c_iflag))) {
+                       dbg("Nothing to change");
+                       return;
+               }
+       }
+
+       dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+           tty->termios->c_cflag,
+           RELEVANT_IFLAG(tty->termios->c_iflag));
+
+       if (old_termios)
+               dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+                   old_termios->c_cflag,
+                   RELEVANT_IFLAG(old_termios->c_iflag));
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       /* change the port settings to the new ones specified */
+       change_port_settings(mos7720_port, old_termios);
+
+       if(!port->read_urb) {
+               dbg("%s","URB KILLED !!!!!\n");
+               return;
+       }
+
+       if(port->read_urb->status != -EINPROGRESS) {
+               port->read_urb->dev = serial->dev;
+               status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+               if (status)
+                       dbg("usb_submit_urb(read bulk) failed, status = %d",
+                           status);
+       }
+       return;
+}
+
+/*
+ * 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 moschip_port *mos7720_port,
+                       unsigned int __user *value)
+{
+       int count;
+       unsigned int result = 0;
+
+       count = mos7720_chars_in_buffer(mos7720_port->port);
+       if (count == 0) {
+               dbg("%s -- Empty", __FUNCTION__);
+               result = TIOCSER_TEMT;
+       }
+
+       if (copy_to_user(value, &result, sizeof(int)))
+               return -EFAULT;
+       return 0;
+}
+
+/*
+ * get_number_bytes_avail - get number of bytes available
+ *
+ * Purpose: Let user call ioctl to get the count of number of bytes available.
+ */
+static int get_number_bytes_avail(struct moschip_port *mos7720_port,
+                                 unsigned int __user *value)
+{
+       unsigned int result = 0;
+       struct tty_struct *tty = mos7720_port->port->tty;
+
+       if (!tty)
+               return -ENOIOCTLCMD;
+
+       result = tty->read_cnt;
+
+       dbg("%s(%d) = %d", __FUNCTION__,  mos7720_port->port->number, result);
+       if (copy_to_user(value, &result, sizeof(int)))
+               return -EFAULT;
+
+       return -ENOIOCTLCMD;
+}
+
+static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
+                         unsigned int __user *value)
+{
+       unsigned int mcr ;
+       unsigned int arg;
+       unsigned char data;
+
+       struct usb_serial_port *port;
+
+       if (mos7720_port == NULL)
+               return -1;
+
+       port = (struct usb_serial_port*)mos7720_port->port;
+       mcr = mos7720_port->shadowMCR;
+
+       if (copy_from_user(&arg, value, sizeof(int)))
+               return -EFAULT;
+
+       switch (cmd) {
+       case TIOCMBIS:
+               if (arg & TIOCM_RTS)
+                       mcr |= UART_MCR_RTS;
+               if (arg & TIOCM_DTR)
+                       mcr |= UART_MCR_RTS;
+               if (arg & TIOCM_LOOP)
+                       mcr |= UART_MCR_LOOP;
+               break;
+
+       case TIOCMBIC:
+               if (arg & TIOCM_RTS)
+                       mcr &= ~UART_MCR_RTS;
+               if (arg & TIOCM_DTR)
+                       mcr &= ~UART_MCR_RTS;
+               if (arg & TIOCM_LOOP)
+                       mcr &= ~UART_MCR_LOOP;
+               break;
+
+       case TIOCMSET:
+               /* turn off the RTS and DTR and LOOPBACK
+                * and then only turn on what was asked to */
+               mcr &=  ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP);
+               mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0);
+               mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0);
+               mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0);
+               break;
+       }
+
+       mos7720_port->shadowMCR = mcr;
+
+       data = mos7720_port->shadowMCR;
+       send_mos_cmd(port->serial, MOS_WRITE,
+                    port->number - port->serial->minor, UART_MCR, &data);
+
+       return 0;
+}
+
+static int get_modem_info(struct moschip_port *mos7720_port,
+                         unsigned int __user *value)
+{
+       unsigned int result = 0;
+       unsigned int msr = mos7720_port->shadowMSR;
+       unsigned int mcr = mos7720_port->shadowMCR;
+
+       result = ((mcr & UART_MCR_DTR)  ? TIOCM_DTR: 0)   /* 0x002 */
+                 | ((mcr & UART_MCR_RTS)       ? TIOCM_RTS: 0)   /* 0x004 */
+                 | ((msr & UART_MSR_CTS)       ? TIOCM_CTS: 0)   /* 0x020 */
+                 | ((msr & UART_MSR_DCD)       ? TIOCM_CAR: 0)   /* 0x040 */
+                 | ((msr & UART_MSR_RI)        ? TIOCM_RI:  0)   /* 0x080 */
+                 | ((msr & UART_MSR_DSR)       ? TIOCM_DSR: 0);  /* 0x100 */
+
+
+       dbg("%s -- %x", __FUNCTION__, result);
+
+       if (copy_to_user(value, &result, sizeof(int)))
+               return -EFAULT;
+       return 0;
+}
+
+static int get_serial_info(struct moschip_port *mos7720_port,
+                          struct serial_struct __user *retinfo)
+{
+       struct serial_struct tmp;
+
+       if (!retinfo)
+               return -EFAULT;
+
+       memset(&tmp, 0, sizeof(tmp));
+
+       tmp.type                = PORT_16550A;
+       tmp.line                = mos7720_port->port->serial->minor;
+       tmp.port                = mos7720_port->port->number;
+       tmp.irq                 = 0;
+       tmp.flags               = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+        tmp.xmit_fifo_size     = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
+       tmp.baud_base           = 9600;
+       tmp.close_delay         = 5*HZ;
+       tmp.closing_wait        = 30*HZ;
+
+       if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
+
+static int mos7720_ioctl(struct usb_serial_port *port, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       struct moschip_port *mos7720_port;
+       struct async_icount cnow;
+       struct async_icount cprev;
+       struct serial_icounter_struct icount;
+
+       mos7720_port = usb_get_serial_port_data(port);
+       if (mos7720_port == NULL)
+               return -ENODEV;
+
+       dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
+
+       switch (cmd) {
+       case TIOCINQ:
+               /* return number of bytes available */
+               dbg("%s (%d) TIOCINQ", __FUNCTION__,  port->number);
+               return get_number_bytes_avail(mos7720_port,
+                                             (unsigned int __user *)arg);
+               break;
+
+       case TIOCSERGETLSR:
+               dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__,  port->number);
+               return get_lsr_info(mos7720_port, (unsigned int __user *)arg);
+               return 0;
+
+       case TIOCMBIS:
+       case TIOCMBIC:
+       case TIOCMSET:
+               dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,
+                   port->number);
+               return set_modem_info(mos7720_port, cmd,
+                                     (unsigned int __user *)arg);
+
+       case TIOCMGET:
+               dbg("%s (%d) TIOCMGET", __FUNCTION__,  port->number);
+               return get_modem_info(mos7720_port,
+                                     (unsigned int __user *)arg);
+
+       case TIOCGSERIAL:
+               dbg("%s (%d) TIOCGSERIAL", __FUNCTION__,  port->number);
+               return get_serial_info(mos7720_port,
+                                      (struct serial_struct __user *)arg);
+
+       case TIOCSSERIAL:
+               dbg("%s (%d) TIOCSSERIAL", __FUNCTION__,  port->number);
+               break;
+
+       case TIOCMIWAIT:
+               dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
+               cprev = mos7720_port->icount;
+               while (1) {
+                       if (signal_pending(current))
+                               return -ERESTARTSYS;
+                       cnow = mos7720_port->icount;
+                       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 */
+               break;
+
+       case TIOCGICOUNT:
+               cnow = mos7720_port->icount;
+               icount.cts = cnow.cts;
+               icount.dsr = cnow.dsr;
+               icount.rng = cnow.rng;
+               icount.dcd = cnow.dcd;
+               icount.rx = cnow.rx;
+               icount.tx = cnow.tx;
+               icount.frame = cnow.frame;
+               icount.overrun = cnow.overrun;
+               icount.parity = cnow.parity;
+               icount.brk = cnow.brk;
+               icount.buf_overrun = cnow.buf_overrun;
+
+               dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
+                   port->number, icount.rx, icount.tx );
+               if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+static int mos7720_startup(struct usb_serial *serial)
+{
+       struct moschip_serial *mos7720_serial;
+       struct moschip_port *mos7720_port;
+       struct usb_device *dev;
+       int i;
+       char data;
+
+       dbg("%s: Entering ..........", __FUNCTION__);
+
+       if (!serial) {
+               dbg("Invalid Handler");
+               return -ENODEV;
+       }
+
+       dev = serial->dev;
+
+       /* create our private serial structure */
+       mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL);
+       if (mos7720_serial == NULL) {
+               err("%s - Out of memory", __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       usb_set_serial_data(serial, mos7720_serial);
+
+       /* we set up the pointers to the endpoints in the mos7720_open *
+        * function, as the structures aren't created yet.             */
+
+       /* set up port private structures */
+       for (i = 0; i < serial->num_ports; ++i) {
+               mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
+               if (mos7720_port == NULL) {
+                       err("%s - Out of memory", __FUNCTION__);
+                       usb_set_serial_data(serial, NULL);
+                       kfree(mos7720_serial);
+                       return -ENOMEM;
+               }
+
+               /* Initialize all port interrupt end point to port 0 int
+                * endpoint.  Our device has only one interrupt endpoint
+                * comman to all ports */
+               serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
+
+               mos7720_port->port = serial->port[i];
+               usb_set_serial_port_data(serial->port[i], mos7720_port);
+
+               dbg("port number is %d", serial->port[i]->number);
+               dbg("serial number is %d", serial->minor);
+       }
+
+
+       /* setting configuration feature to one */
+       usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                       (__u8)0x03, 0x00,0x01,0x00, NULL, 0x00, 5*HZ);
+
+       send_mos_cmd(serial,MOS_READ,0x00, UART_LSR, &data);  // LSR For Port 1
+       dbg("LSR:%x",data);
+
+       send_mos_cmd(serial,MOS_READ,0x01, UART_LSR, &data);  // LSR For Port 2
+       dbg("LSR:%x",data);
+
+       return 0;
+}
+
+static void mos7720_shutdown(struct usb_serial *serial)
+{
+       int i;
+
+       /* free private structure allocated for serial port */
+       for (i=0; i < serial->num_ports; ++i) {
+               kfree(usb_get_serial_port_data(serial->port[i]));
+               usb_set_serial_port_data(serial->port[i], NULL);
+       }
+
+       /* free private structure allocated for serial device */
+       kfree(usb_get_serial_data(serial));
+       usb_set_serial_data(serial, NULL);
+}
+
+static struct usb_serial_driver moschip7720_2port_driver = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "moschip7720",
+       },
+       .description            = "Moschip 2 port adapter",
+       .id_table               = moschip_port_id_table,
+       .num_interrupt_in       = 1,
+       .num_bulk_in            = 2,
+       .num_bulk_out           = 2,
+       .num_ports              = 2,
+       .open                   = mos7720_open,
+       .close                  = mos7720_close,
+       .throttle               = mos7720_throttle,
+       .unthrottle             = mos7720_unthrottle,
+       .attach                 = mos7720_startup,
+       .shutdown               = mos7720_shutdown,
+       .ioctl                  = mos7720_ioctl,
+       .set_termios            = mos7720_set_termios,
+       .write                  = mos7720_write,
+       .write_room             = mos7720_write_room,
+       .chars_in_buffer        = mos7720_chars_in_buffer,
+       .break_ctl              = mos7720_break,
+       .read_bulk_callback     = mos7720_bulk_in_callback,
+};
+
+static struct usb_driver usb_driver = {
+       .name =         "moschip7720",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     moschip_port_id_table,
+};
+
+static int __init moschip7720_init(void)
+{
+       int retval;
+
+       dbg("%s: Entering ..........", __FUNCTION__);
+
+       /* Register with the usb serial */
+       retval = usb_serial_register(&moschip7720_2port_driver);
+       if (retval)
+               goto failed_port_device_register;
+
+       info(DRIVER_DESC " " DRIVER_VERSION);
+
+       /* Register with the usb */
+       retval = usb_register(&usb_driver);
+       if (retval)
+               goto failed_usb_register;
+
+       return 0;
+
+failed_usb_register:
+       usb_serial_deregister(&moschip7720_2port_driver);
+
+failed_port_device_register:
+       return retval;
+}
+
+static void __exit moschip7720_exit(void)
+{
+       usb_deregister(&usb_driver);
+       usb_serial_deregister(&moschip7720_2port_driver);
+}
+
+module_init(moschip7720_init);
+module_exit(moschip7720_exit);
+
+/* Module information */
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
index 021be39fe16e04b1ca9f172ec8206fceda2cdb5e..5b71962d0351d3a740be7d8a1d3e3aecef0a070d 100644 (file)
@@ -2413,11 +2413,12 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
        }
 
        mos7840_port = mos7840_get_port_private(port);
-       tty = mos7840_port->port->tty;
 
        if (mos7840_port == NULL)
                return -1;
 
+       tty = mos7840_port->port->tty;
+
        dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
 
        switch (cmd) {
index d29638daa987fb9a2f37f58a23caccf1a1b4f587..ea16572d19f89219b013dc2f81af344f534e38bb 100644 (file)
@@ -1,21 +1,35 @@
 /*
- * Sierra Wireless CDMA Wireless Serial USB driver
- *
- * Current Copy modified by: Kevin Lloyd <linux@sierrawireless.com>
- * Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License version
- *     2 as published by the Free Software Foundation.
- */
+  USB Driver for Sierra Wireless
+
+  Copyright (C) 2006  Kevin Lloyd <linux@sierrawireless.com>
+
+  IMPORTANT DISCLAIMER: This driver is not commercially supported by
+  Sierra Wireless. Use at your own risk.
+
+  This driver is free software; you can redistribute it and/or modify
+  it under the terms of Version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
+  Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
+
+  History:
+*/
+
+#define DRIVER_VERSION "v.1.0.5"
+#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
+#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
 #include <linux/kernel.h>
-#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
 #include <linux/tty.h>
+#include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
+
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
@@ -23,53 +37,674 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
        { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
-       /* Following devices are supported in the airprime.c driver */
-       /* { USB_DEVICE(0x1199, 0x0112) }, */   /* Sierra Wireless AirCard 580 */
-       /* { USB_DEVICE(0x0F3D, 0x0112) }, */   /* AirPrime/Sierra PC 5220 */
+
+       { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
+       { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
        { }
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+static struct usb_device_id id_table_1port [] = {
+       { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
+       { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+       { }
+};
+
+static struct usb_device_id id_table_3port [] = {
+       { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
+       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
+       { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
+       { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+       { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+       { }
+};
+
 static struct usb_driver sierra_driver = {
-       .name =         "sierra_wireless",
-       .probe =        usb_serial_probe,
-       .disconnect =   usb_serial_disconnect,
-       .id_table =     id_table,
+       .name       = "sierra",
+       .probe      = usb_serial_probe,
+       .disconnect = usb_serial_disconnect,
+       .id_table   = id_table,
+       .no_dynamic_id =        1,
+};
+
+
+static int debug;
+
+/* per port private data */
+#define N_IN_URB       4
+#define N_OUT_URB      1
+#define IN_BUFLEN      4096
+#define OUT_BUFLEN     128
+
+struct sierra_port_private {
+       /* Input endpoints and buffer for this port */
+       struct urb *in_urbs[N_IN_URB];
+       char in_buffer[N_IN_URB][IN_BUFLEN];
+       /* Output endpoints and buffer for this port */
+       struct urb *out_urbs[N_OUT_URB];
+       char out_buffer[N_OUT_URB][OUT_BUFLEN];
+
+       /* Settings for the port */
+       int rts_state;  /* Handshaking pins (outputs) */
+       int dtr_state;
+       int cts_state;  /* Handshaking pins (inputs) */
+       int dsr_state;
+       int dcd_state;
+       int ri_state;
+
+       unsigned long tx_start_time[N_OUT_URB];
+};
+
+static int sierra_send_setup(struct usb_serial_port *port)
+{
+       struct usb_serial *serial = port->serial;
+       struct sierra_port_private *portdata;
+
+       dbg("%s", __FUNCTION__);
+
+       portdata = usb_get_serial_port_data(port);
+
+       if (port->tty) {
+               int val = 0;
+               if (portdata->dtr_state)
+                       val |= 0x01;
+               if (portdata->rts_state)
+                       val |= 0x02;
+
+               return usb_control_msg(serial->dev,
+                               usb_rcvctrlpipe(serial->dev, 0),
+                               0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+       }
+
+       return 0;
+}
+
+static void sierra_rx_throttle(struct usb_serial_port *port)
+{
+       dbg("%s", __FUNCTION__);
+}
+
+static void sierra_rx_unthrottle(struct usb_serial_port *port)
+{
+       dbg("%s", __FUNCTION__);
+}
+
+static void sierra_break_ctl(struct usb_serial_port *port, int break_state)
+{
+       /* Unfortunately, I don't know how to send a break */
+       dbg("%s", __FUNCTION__);
+}
+
+static void sierra_set_termios(struct usb_serial_port *port,
+                       struct termios *old_termios)
+{
+       dbg("%s", __FUNCTION__);
+
+       sierra_send_setup(port);
+}
+
+static int sierra_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+       unsigned int value;
+       struct sierra_port_private *portdata;
+
+       portdata = usb_get_serial_port_data(port);
+
+       value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
+               ((portdata->dtr_state) ? TIOCM_DTR : 0) |
+               ((portdata->cts_state) ? TIOCM_CTS : 0) |
+               ((portdata->dsr_state) ? TIOCM_DSR : 0) |
+               ((portdata->dcd_state) ? TIOCM_CAR : 0) |
+               ((portdata->ri_state) ? TIOCM_RNG : 0);
+
+       return value;
+}
+
+static int sierra_tiocmset(struct usb_serial_port *port, struct file *file,
+                       unsigned int set, unsigned int clear)
+{
+       struct sierra_port_private *portdata;
+
+       portdata = usb_get_serial_port_data(port);
+
+       if (set & TIOCM_RTS)
+               portdata->rts_state = 1;
+       if (set & TIOCM_DTR)
+               portdata->dtr_state = 1;
+
+       if (clear & TIOCM_RTS)
+               portdata->rts_state = 0;
+       if (clear & TIOCM_DTR)
+               portdata->dtr_state = 0;
+       return sierra_send_setup(port);
+}
+
+static int sierra_ioctl(struct usb_serial_port *port, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+/* Write */
+static int sierra_write(struct usb_serial_port *port,
+                       const unsigned char *buf, int count)
+{
+       struct sierra_port_private *portdata;
+       int i;
+       int left, todo;
+       struct urb *this_urb = NULL; /* spurious */
+       int err;
+
+       portdata = usb_get_serial_port_data(port);
+
+       dbg("%s: write (%d chars)", __FUNCTION__, count);
+
+       i = 0;
+       left = count;
+       for (i=0; left > 0 && i < N_OUT_URB; i++) {
+               todo = left;
+               if (todo > OUT_BUFLEN)
+                       todo = OUT_BUFLEN;
+
+               this_urb = portdata->out_urbs[i];
+               if (this_urb->status == -EINPROGRESS) {
+                       if (time_before(jiffies,
+                                       portdata->tx_start_time[i] + 10 * HZ))
+                               continue;
+                       usb_unlink_urb(this_urb);
+                       continue;
+               }
+               if (this_urb->status != 0)
+                       dbg("usb_write %p failed (err=%d)",
+                               this_urb, this_urb->status);
+
+               dbg("%s: endpoint %d buf %d", __FUNCTION__,
+                       usb_pipeendpoint(this_urb->pipe), i);
+
+               /* send the data */
+               memcpy (this_urb->transfer_buffer, buf, todo);
+               this_urb->transfer_buffer_length = todo;
+
+               this_urb->dev = port->serial->dev;
+               err = usb_submit_urb(this_urb, GFP_ATOMIC);
+               if (err) {
+                       dbg("usb_submit_urb %p (write bulk) failed "
+                               "(%d, has %d)", this_urb,
+                               err, this_urb->status);
+                       continue;
+               }
+               portdata->tx_start_time[i] = jiffies;
+               buf += todo;
+               left -= todo;
+       }
+
+       count -= left;
+       dbg("%s: wrote (did %d)", __FUNCTION__, count);
+       return count;
+}
+
+static void sierra_indat_callback(struct urb *urb)
+{
+       int err;
+       int endpoint;
+       struct usb_serial_port *port;
+       struct tty_struct *tty;
+       unsigned char *data = urb->transfer_buffer;
+
+       dbg("%s: %p", __FUNCTION__, urb);
+
+       endpoint = usb_pipeendpoint(urb->pipe);
+       port = (struct usb_serial_port *) urb->context;
+
+       if (urb->status) {
+               dbg("%s: nonzero status: %d on endpoint %02x.",
+                   __FUNCTION__, urb->status, endpoint);
+       } else {
+               tty = port->tty;
+               if (urb->actual_length) {
+                       tty_buffer_request_room(tty, urb->actual_length);
+                       tty_insert_flip_string(tty, data, urb->actual_length);
+                       tty_flip_buffer_push(tty);
+               } else {
+                       dbg("%s: empty read urb received", __FUNCTION__);
+               }
+
+               /* Resubmit urb so we continue receiving */
+               if (port->open_count && urb->status != -ESHUTDOWN) {
+                       err = usb_submit_urb(urb, GFP_ATOMIC);
+                       if (err)
+                               printk(KERN_ERR "%s: resubmit read urb failed. "
+                                       "(%d)", __FUNCTION__, err);
+               }
+       }
+       return;
+}
+
+static void sierra_outdat_callback(struct urb *urb)
+{
+       struct usb_serial_port *port;
+
+       dbg("%s", __FUNCTION__);
+
+       port = (struct usb_serial_port *) urb->context;
+
+       usb_serial_port_softint(port);
+}
+
+static void sierra_instat_callback(struct urb *urb)
+{
+       int err;
+       struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+       struct sierra_port_private *portdata = usb_get_serial_port_data(port);
+       struct usb_serial *serial = port->serial;
+
+       dbg("%s", __FUNCTION__);
+       dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
+
+       if (urb->status == 0) {
+               struct usb_ctrlrequest *req_pkt =
+                               (struct usb_ctrlrequest *)urb->transfer_buffer;
+
+               if (!req_pkt) {
+                       dbg("%s: NULL req_pkt\n", __FUNCTION__);
+                       return;
+               }
+               if ((req_pkt->bRequestType == 0xA1) &&
+                               (req_pkt->bRequest == 0x20)) {
+                       int old_dcd_state;
+                       unsigned char signals = *((unsigned char *)
+                                       urb->transfer_buffer +
+                                       sizeof(struct usb_ctrlrequest));
+
+                       dbg("%s: signal x%x", __FUNCTION__, signals);
+
+                       old_dcd_state = portdata->dcd_state;
+                       portdata->cts_state = 1;
+                       portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
+                       portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
+                       portdata->ri_state = ((signals & 0x08) ? 1 : 0);
+
+                       if (port->tty && !C_CLOCAL(port->tty) &&
+                                       old_dcd_state && !portdata->dcd_state)
+                               tty_hangup(port->tty);
+               } else {
+                       dbg("%s: type %x req %x", __FUNCTION__,
+                               req_pkt->bRequestType,req_pkt->bRequest);
+               }
+       } else
+               dbg("%s: error %d", __FUNCTION__, urb->status);
+
+       /* Resubmit urb so we continue receiving IRQ data */
+       if (urb->status != -ESHUTDOWN) {
+               urb->dev = serial->dev;
+               err = usb_submit_urb(urb, GFP_ATOMIC);
+               if (err)
+                       dbg("%s: resubmit intr urb failed. (%d)",
+                               __FUNCTION__, err);
+       }
+}
+
+static int sierra_write_room(struct usb_serial_port *port)
+{
+       struct sierra_port_private *portdata;
+       int i;
+       int data_len = 0;
+       struct urb *this_urb;
+
+       portdata = usb_get_serial_port_data(port);
+
+       for (i=0; i < N_OUT_URB; i++) {
+               this_urb = portdata->out_urbs[i];
+               if (this_urb && this_urb->status != -EINPROGRESS)
+                       data_len += OUT_BUFLEN;
+       }
+
+       dbg("%s: %d", __FUNCTION__, data_len);
+       return data_len;
+}
+
+static int sierra_chars_in_buffer(struct usb_serial_port *port)
+{
+       struct sierra_port_private *portdata;
+       int i;
+       int data_len = 0;
+       struct urb *this_urb;
+
+       portdata = usb_get_serial_port_data(port);
+
+       for (i=0; i < N_OUT_URB; i++) {
+               this_urb = portdata->out_urbs[i];
+               if (this_urb && this_urb->status == -EINPROGRESS)
+                       data_len += this_urb->transfer_buffer_length;
+       }
+       dbg("%s: %d", __FUNCTION__, data_len);
+       return data_len;
+}
+
+static int sierra_open(struct usb_serial_port *port, struct file *filp)
+{
+       struct sierra_port_private *portdata;
+       struct usb_serial *serial = port->serial;
+       int i, err;
+       struct urb *urb;
+
+       portdata = usb_get_serial_port_data(port);
+
+       dbg("%s", __FUNCTION__);
+
+       /* Set some sane defaults */
+       portdata->rts_state = 1;
+       portdata->dtr_state = 1;
+
+       /* Reset low level data toggle and start reading from endpoints */
+       for (i = 0; i < N_IN_URB; i++) {
+               urb = portdata->in_urbs[i];
+               if (! urb)
+                       continue;
+               if (urb->dev != serial->dev) {
+                       dbg("%s: dev %p != %p", __FUNCTION__,
+                               urb->dev, serial->dev);
+                       continue;
+               }
+
+               /*
+                * make sure endpoint data toggle is synchronized with the
+                * device
+                */
+               usb_clear_halt(urb->dev, urb->pipe);
+
+               err = usb_submit_urb(urb, GFP_KERNEL);
+               if (err) {
+                       dbg("%s: submit urb %d failed (%d) %d",
+                               __FUNCTION__, i, err,
+                               urb->transfer_buffer_length);
+               }
+       }
+
+       /* Reset low level data toggle on out endpoints */
+       for (i = 0; i < N_OUT_URB; i++) {
+               urb = portdata->out_urbs[i];
+               if (! urb)
+                       continue;
+               urb->dev = serial->dev;
+               /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                               usb_pipeout(urb->pipe), 0); */
+       }
+
+       port->tty->low_latency = 1;
+
+       sierra_send_setup(port);
+
+       return (0);
+}
+
+static inline void stop_urb(struct urb *urb)
+{
+       if (urb && urb->status == -EINPROGRESS)
+               usb_kill_urb(urb);
+}
+
+static void sierra_close(struct usb_serial_port *port, struct file *filp)
+{
+       int i;
+       struct usb_serial *serial = port->serial;
+       struct sierra_port_private *portdata;
+
+       dbg("%s", __FUNCTION__);
+       portdata = usb_get_serial_port_data(port);
+
+       portdata->rts_state = 0;
+       portdata->dtr_state = 0;
+
+       if (serial->dev) {
+               sierra_send_setup(port);
+
+               /* Stop reading/writing urbs */
+               for (i = 0; i < N_IN_URB; i++)
+                       stop_urb(portdata->in_urbs[i]);
+               for (i = 0; i < N_OUT_URB; i++)
+                       stop_urb(portdata->out_urbs[i]);
+       }
+       port->tty = NULL;
+}
+
+/* Helper functions used by sierra_setup_urbs */
+static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
+                                   int dir, void *ctx, char *buf, int len,
+                                   usb_complete_t callback)
+{
+       struct urb *urb;
+
+       if (endpoint == -1)
+               return NULL;            /* endpoint not needed */
+
+       urb = usb_alloc_urb(0, GFP_KERNEL);             /* No ISO */
+       if (urb == NULL) {
+               dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
+               return NULL;
+       }
+
+               /* Fill URB using supplied data. */
+       usb_fill_bulk_urb(urb, serial->dev,
+                     usb_sndbulkpipe(serial->dev, endpoint) | dir,
+                     buf, len, callback, ctx);
+
+       return urb;
+}
+
+/* Setup urbs */
+static void sierra_setup_urbs(struct usb_serial *serial)
+{
+       int i,j;
+       struct usb_serial_port *port;
+       struct sierra_port_private *portdata;
+
+       dbg("%s", __FUNCTION__);
+
+       for (i = 0; i < serial->num_ports; i++) {
+               port = serial->port[i];
+               portdata = usb_get_serial_port_data(port);
+
+       /* Do indat endpoints first */
+               for (j = 0; j < N_IN_URB; ++j) {
+                       portdata->in_urbs[j] = sierra_setup_urb (serial,
+                       port->bulk_in_endpointAddress, USB_DIR_IN, port,
+                       portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback);
+               }
+
+               /* outdat endpoints */
+               for (j = 0; j < N_OUT_URB; ++j) {
+                       portdata->out_urbs[j] = sierra_setup_urb (serial,
+                       port->bulk_out_endpointAddress, USB_DIR_OUT, port,
+                       portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback);
+               }
+       }
+}
+
+static int sierra_startup(struct usb_serial *serial)
+{
+       int i, err;
+       struct usb_serial_port *port;
+       struct sierra_port_private *portdata;
+
+       dbg("%s", __FUNCTION__);
+
+       /* Now setup per port private data */
+       for (i = 0; i < serial->num_ports; i++) {
+               port = serial->port[i];
+               portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
+               if (!portdata) {
+                       dbg("%s: kmalloc for sierra_port_private (%d) failed!.",
+                                       __FUNCTION__, i);
+                       return (1);
+               }
+
+               usb_set_serial_port_data(port, portdata);
+
+               if (! port->interrupt_in_urb)
+                       continue;
+               err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+               if (err)
+                       dbg("%s: submit irq_in urb failed %d",
+                               __FUNCTION__, err);
+       }
+
+       sierra_setup_urbs(serial);
+
+       return (0);
+}
+
+static void sierra_shutdown(struct usb_serial *serial)
+{
+       int i, j;
+       struct usb_serial_port *port;
+       struct sierra_port_private *portdata;
+
+       dbg("%s", __FUNCTION__);
+
+       /* Stop reading/writing urbs */
+       for (i = 0; i < serial->num_ports; ++i) {
+               port = serial->port[i];
+               portdata = usb_get_serial_port_data(port);
+               for (j = 0; j < N_IN_URB; j++)
+                       stop_urb(portdata->in_urbs[j]);
+               for (j = 0; j < N_OUT_URB; j++)
+                       stop_urb(portdata->out_urbs[j]);
+       }
+
+       /* Now free them */
+       for (i = 0; i < serial->num_ports; ++i) {
+               port = serial->port[i];
+               portdata = usb_get_serial_port_data(port);
+
+               for (j = 0; j < N_IN_URB; j++) {
+                       if (portdata->in_urbs[j]) {
+                               usb_free_urb(portdata->in_urbs[j]);
+                               portdata->in_urbs[j] = NULL;
+                       }
+               }
+               for (j = 0; j < N_OUT_URB; j++) {
+                       if (portdata->out_urbs[j]) {
+                               usb_free_urb(portdata->out_urbs[j]);
+                               portdata->out_urbs[j] = NULL;
+                       }
+               }
+       }
+
+       /* Now free per port private data */
+       for (i = 0; i < serial->num_ports; i++) {
+               port = serial->port[i];
+               kfree(usb_get_serial_port_data(port));
+       }
+}
+
+static struct usb_serial_driver sierra_1port_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "sierra1",
+       },
+       .description       = "Sierra USB modem (1 port)",
+       .id_table          = id_table_1port,
+       .num_interrupt_in  = NUM_DONT_CARE,
+       .num_bulk_in       = 1,
+       .num_bulk_out      = 1,
+       .num_ports         = 1,
+       .open              = sierra_open,
+       .close             = sierra_close,
+       .write             = sierra_write,
+       .write_room        = sierra_write_room,
+       .chars_in_buffer   = sierra_chars_in_buffer,
+       .throttle          = sierra_rx_throttle,
+       .unthrottle        = sierra_rx_unthrottle,
+       .ioctl             = sierra_ioctl,
+       .set_termios       = sierra_set_termios,
+       .break_ctl         = sierra_break_ctl,
+       .tiocmget          = sierra_tiocmget,
+       .tiocmset          = sierra_tiocmset,
+       .attach            = sierra_startup,
+       .shutdown          = sierra_shutdown,
+       .read_int_callback = sierra_instat_callback,
 };
 
-static struct usb_serial_driver sierra_device = {
+static struct usb_serial_driver sierra_3port_device = {
        .driver = {
-       .owner =                THIS_MODULE,
-       .name =                 "Sierra_Wireless",
+               .owner =        THIS_MODULE,
+               .name =         "sierra3",
        },
-       .id_table =             id_table,
-       .num_interrupt_in =     NUM_DONT_CARE,
-       .num_bulk_in =          NUM_DONT_CARE,
-       .num_bulk_out =         NUM_DONT_CARE,
-       .num_ports =            3,
+       .description       = "Sierra USB modem (3 port)",
+       .id_table          = id_table_3port,
+       .num_interrupt_in  = NUM_DONT_CARE,
+       .num_bulk_in       = 3,
+       .num_bulk_out      = 3,
+       .num_ports         = 3,
+       .open              = sierra_open,
+       .close             = sierra_close,
+       .write             = sierra_write,
+       .write_room        = sierra_write_room,
+       .chars_in_buffer   = sierra_chars_in_buffer,
+       .throttle          = sierra_rx_throttle,
+       .unthrottle        = sierra_rx_unthrottle,
+       .ioctl             = sierra_ioctl,
+       .set_termios       = sierra_set_termios,
+       .break_ctl         = sierra_break_ctl,
+       .tiocmget          = sierra_tiocmget,
+       .tiocmset          = sierra_tiocmset,
+       .attach            = sierra_startup,
+       .shutdown          = sierra_shutdown,
+       .read_int_callback = sierra_instat_callback,
 };
 
+/* Functions used by new usb-serial code. */
 static int __init sierra_init(void)
 {
        int retval;
-
-       retval = usb_serial_register(&sierra_device);
+       retval = usb_serial_register(&sierra_1port_device);
+       if (retval)
+               goto failed_1port_device_register;
+       retval = usb_serial_register(&sierra_3port_device);
        if (retval)
-               return retval;
+               goto failed_3port_device_register;
+
+
        retval = usb_register(&sierra_driver);
        if (retval)
-               usb_serial_deregister(&sierra_device);
+               goto failed_driver_register;
+
+       info(DRIVER_DESC ": " DRIVER_VERSION);
+
+       return 0;
+
+failed_driver_register:
+       usb_serial_deregister(&sierra_3port_device);
+failed_3port_device_register:
+       usb_serial_deregister(&sierra_1port_device);
+failed_1port_device_register:
        return retval;
 }
 
 static void __exit sierra_exit(void)
 {
-       usb_deregister(&sierra_driver);
-       usb_serial_deregister(&sierra_device);
+       usb_deregister (&sierra_driver);
+       usb_serial_deregister(&sierra_1port_device);
+       usb_serial_deregister(&sierra_3port_device);
 }
 
 module_init(sierra_init);
 module_exit(sierra_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_USB_DEBUG
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages");
+#endif
+
index c9a8d50106d1a3bef5b9f1359baad58d015f1725..37ed8e0f2dc8fd4015f09a2c1a52e70f3bff36f7 100644 (file)
@@ -55,7 +55,8 @@ UNUSUAL_DEV(  0x03eb, 0x2002, 0x0100, 0x0100,
                 US_SC_DEVICE, US_PR_DEVICE, NULL,
                 US_FL_IGNORE_RESIDUE),
 
-UNUSUAL_DEV(  0x03ee, 0x6901, 0x0000, 0x0100,
+/* modified by Tobias Lorenz <tobias.lorenz@gmx.net> */
+UNUSUAL_DEV(  0x03ee, 0x6901, 0x0000, 0x0200,
                "Mitsumi",
                "USB FDD",
                US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -182,6 +183,20 @@ UNUSUAL_DEV(  0x0421, 0x044e, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
 
+/* Reported by Bardur Arantsson <bardur@scientician.net> */
+UNUSUAL_DEV(  0x0421, 0x047c, 0x0370, 0x0370,
+               "Nokia",
+               "6131",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Alex Corcoles <alex@corcoles.net> */
+UNUSUAL_DEV(  0x0421, 0x0495, 0x0370, 0x0370,
+               "Nokia",
+               "6234",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_MAX_SECTORS_64 ),
+
 /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
 UNUSUAL_DEV(  0x0424, 0x0fdc, 0x0210, 0x0210,
                "SMSC",
@@ -1291,6 +1306,13 @@ UNUSUAL_DEV(  0x0fce, 0xe030, 0x0000, 0x0000,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY ),
 
+/* Reported by Jan Mate <mate@fiit.stuba.sk> */
+UNUSUAL_DEV(  0x0fce, 0xe030, 0x0000, 0x0000,
+               "Sony Ericsson",
+               "P990i",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY ),
+
 /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
  * Tested on hardware version 1.10.
  * Entry is needed only for the initializer function override.
index f5cc65dd7d0d31e4e08abfaf19a488c6580c8dc0..68731e0923a4caebc86dd6134248ddc790691795 100644 (file)
 #define SSSR_TINT              (1 << 19)       /* Receiver Time-out Interrupt */
 #define SSSR_PINT              (1 << 18)       /* Peripheral Trailing Byte Interrupt */
 
+#define SSPSP_FSRT             (1 << 25)       /* Frame Sync Relative Timing */
 #define SSPSP_DMYSTOP(x)       (x << 23)       /* Dummy Stop */
 #define SSPSP_SFRMWDTH(x)      (x << 16)       /* Serial Frame Width */
 #define SSPSP_SFRMDLY(x)       (x << 9)        /* Serial Frame Delay */
index 1b8e8a304800748cd43179add4c10de2df40a91b..3f37ca07806dc046f25dd832f8b9a52d4da86af2 100644 (file)
 #define GPIO_JORNADA720_KEYBOARD_IRQ   IRQ_GPIO0
 #define GPIO_JORNADA720_MOUSE_IRQ              IRQ_GPIO9
 
+/* MCU COMMANDS */
+#define MCU_GetBatteryData  0xc0
+#define MCU_GetScanKeyCode  0x90
+#define MCU_GetTouchSamples 0xa0
+#define MCU_GetContrast     0xD0
+#define MCU_SetContrast     0xD1
+#define MCU_GetBrightness   0xD2
+#define MCU_SetBrightness   0xD3
+#define MCU_ContrastOff     0xD8
+#define MCU_BrightnessOff   0xD9
+#define MCU_PWMOFF          0xDF
+#define MCU_TxDummy         0x11
+#define MCU_ErrorCode       0x00
+
 #ifndef __ASSEMBLY__
 
 void jornada720_mcu_init(void);