]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/bnx2-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Wed, 1 Feb 2006 03:26:25 +0000 (19:26 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 1 Feb 2006 03:26:25 +0000 (19:26 -0800)
245 files changed:
Documentation/feature-removal-schedule.txt
Documentation/scsi/ChangeLog.megaraid_sas [new file with mode: 0644]
Documentation/scsi/aic79xx.txt
Documentation/scsi/aic7xxx.txt
Documentation/usb/et61x251.txt [new file with mode: 0644]
Documentation/usb/sn9c102.txt
Documentation/usb/w9968cf.txt
MAINTAINERS
arch/arm/configs/bast_defconfig
arch/arm/configs/collie_defconfig
arch/arm/configs/s3c2410_defconfig
arch/arm/kernel/calls.S
arch/arm/kernel/entry-common.S
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-s3c2410/cpu.h
arch/arm/mach-s3c2410/devs.c
arch/arm/mach-s3c2410/dma.c
arch/arm/mach-s3c2410/sleep.S
arch/arm/mm/ioremap.c
arch/arm/mm/mm-armv.c
arch/i386/kernel/cpu/centaur.c
arch/i386/kernel/cpu/cpufreq/Kconfig
arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
arch/i386/kernel/cpu/intel_cacheinfo.c
arch/i386/kernel/cpu/mtrr/main.c
arch/i386/pci/irq.c
arch/i386/pci/mmconfig.c
arch/ia64/kernel/mca_asm.S
arch/ia64/kernel/unaligned.c
arch/ia64/sn/kernel/io_init.c
arch/ia64/sn/kernel/xpc_channel.c
arch/ia64/sn/pci/pci_dma.c
arch/ppc/syslib/mv64x60.c
arch/sparc/kernel/entry.S
arch/sparc/math-emu/math.c
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/sys32.S
arch/sparc64/kernel/systbls.S
arch/x86_64/pci/mmconfig.c
block/elevator.c
block/ll_rw_blk.c
drivers/block/ub.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/ati-agp.c
drivers/char/agp/frontend.c
drivers/char/agp/intel-agp.c
drivers/char/agp/isoch.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_userspace.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/mthca/mthca_av.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/input/touchscreen/ads7846.c
drivers/message/fusion/Makefile
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptscsih.h
drivers/message/fusion/mptspi.c
drivers/misc/ibmasm/uart.c
drivers/net/Kconfig
drivers/net/acenic.c
drivers/net/b44.c
drivers/net/bonding/bond_main.c
drivers/net/mv643xx_eth.c
drivers/net/s2io.c
drivers/net/wireless/hostap/Kconfig
drivers/net/wireless/ipw2100.c
drivers/net/wireless/ipw2200.c
drivers/net/wireless/orinoco_cs.c
drivers/pci/hotplug/Kconfig
drivers/pci/hotplug/acpiphp_ibm.c
drivers/pci/hotplug/ibmphp_core.c
drivers/pci/hotplug/rpadlpar_core.c
drivers/pci/hotplug/rpaphp.h
drivers/pci/hotplug/rpaphp_core.c
drivers/pci/hotplug/rpaphp_pci.c
drivers/pci/hotplug/rpaphp_slot.c
drivers/pci/hotplug/shpchp.h
drivers/pci/hotplug/shpchp_ctrl.c
drivers/pci/msi.c
drivers/pci/msi.h
drivers/pci/pci.c
drivers/pci/setup-res.c
drivers/scsi/aic7xxx/Kconfig.aic79xx
drivers/scsi/aic7xxx/aic79xx.h
drivers/scsi/aic7xxx/aic79xx.reg
drivers/scsi/aic7xxx/aic79xx.seq
drivers/scsi/aic7xxx/aic79xx_core.c
drivers/scsi/aic7xxx/aic79xx_inline.h
drivers/scsi/aic7xxx/aic79xx_osm.c
drivers/scsi/aic7xxx/aic79xx_osm.h
drivers/scsi/aic7xxx/aic79xx_osm_pci.c
drivers/scsi/aic7xxx/aic79xx_pci.c
drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
drivers/scsi/aic7xxx/aicasm/aicasm.c
drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
drivers/scsi/dc395x.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvscsi.h
drivers/scsi/ibmvscsi/iseries_vscsi.c
drivers/scsi/ibmvscsi/rpa_vscsi.c
drivers/scsi/ips.c
drivers/scsi/libata-scsi.c
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/qla1280.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_transport_sas.c
drivers/scsi/sg.c
drivers/scsi/st.c
drivers/serial/21285.c
drivers/serial/8250.c
drivers/serial/Kconfig
drivers/serial/amba-pl010.c
drivers/serial/clps711x.c
drivers/serial/imx.c
drivers/serial/s3c2410.c
drivers/serial/sa1100.c
drivers/serial/serial_core.c
drivers/serial/serial_lh7a40x.c
drivers/serial/sh-sci.c
drivers/serial/sunsu.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/atm/usbatm.h
drivers/usb/atm/xusbatm.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/usblp.c
drivers/usb/core/message.c
drivers/usb/core/urb.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/zero.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/ohci-au1xxx.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/uhci-q.c
drivers/usb/input/hid-core.c
drivers/usb/input/hiddev.c
drivers/usb/input/touchkitusb.c
drivers/usb/input/yealink.c
drivers/usb/media/Kconfig
drivers/usb/media/Makefile
drivers/usb/media/et61x251.h [new file with mode: 0644]
drivers/usb/media/et61x251_core.c [new file with mode: 0644]
drivers/usb/media/et61x251_sensor.h [new file with mode: 0644]
drivers/usb/media/et61x251_tas5130d1b.c [new file with mode: 0644]
drivers/usb/media/ov511.c
drivers/usb/media/pwc/pwc-ctrl.c
drivers/usb/media/sn9c102.h
drivers/usb/media/sn9c102_core.c
drivers/usb/media/sn9c102_hv7131d.c
drivers/usb/media/sn9c102_mi0343.c
drivers/usb/media/sn9c102_ov7630.c
drivers/usb/media/sn9c102_pas106b.c
drivers/usb/media/sn9c102_sensor.h
drivers/usb/media/sn9c102_tas5110c1b.c
drivers/usb/media/sn9c102_tas5130d1b.c
drivers/usb/media/w9968cf.c
drivers/usb/media/w9968cf.h
drivers/usb/media/w9968cf_vpp.h
drivers/usb/misc/auerswald.c
drivers/usb/misc/ldusb.c
drivers/usb/net/asix.c
drivers/usb/serial/cp2101.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/storage/initializers.c
drivers/usb/storage/initializers.h
drivers/usb/storage/libusual.c
drivers/usb/storage/unusual_devs.h
drivers/usb/usb-skeleton.c
drivers/video/amba-clcd.c
drivers/video/cyblafb.c
fs/bio.c
include/asm-arm/arch-s3c2410/debug-macro.S
include/asm-arm/arch-s3c2410/map.h
include/asm-arm/arch-s3c2410/regs-serial.h
include/asm-arm/arch-s3c2410/uncompress.h
include/asm-arm/mach/map.h
include/asm-arm/pgtable.h
include/asm-ia64/sn/sn_feature_sets.h
include/asm-sparc64/spinlock.h
include/linux/agpgart.h
include/linux/blkdev.h
include/linux/cpufreq.h
include/linux/netfilter/x_tables.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/serial_8250.h
include/linux/serial_core.h
include/linux/usb_ch9.h
include/linux/videodev2.h
include/net/ieee80211.h
include/net/route.h
include/scsi/scsi_device.h
include/scsi/scsi_host.h
kernel/rcutorture.c
kernel/sched.c
kernel/time.c
kernel/user.c
net/bridge/br_if.c
net/bridge/br_private.h
net/core/dev.c
net/core/filter.c
net/core/skbuff.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/ieee80211/ieee80211_rx.c
net/ieee80211/ieee80211_wx.c
net/ipv4/igmp.c
net/ipv4/tcp_htcp.c
net/ipv4/tcp_ipv4.c
net/ipv6/mcast.c
net/ipv6/tcp_ipv6.c
net/key/af_key.c
net/packet/af_packet.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
security/seclvl.c
sound/oss/au1550_ac97.c

index b4a1ea76269857137a659e69102b1223b715f6cf..4d4897c8ef963284664e23729ca792f302fc464b 100644 (file)
@@ -148,3 +148,17 @@ Why:       The 8250 serial driver now has the ability to deal with the differences
        brother on Alchemy SOCs.  The loss of features is not considered an
        issue.
 Who:   Ralf Baechle <ralf@linux-mips.org>
+
+---------------------------
+
+What:  Legacy /proc/pci interface (PCI_LEGACY_PROC)
+When:  March 2006
+Why:   deprecated since 2.5.53 in favor of lspci(8)
+Who:   Adrian Bunk <bunk@stusta.de>
+
+---------------------------
+
+What:  pci_module_init(driver)
+When:  January 2007
+Why:   Is replaced by pci_register_driver(pci_driver).
+Who:   Richard Knutsson <ricknu-0@student.ltu.se> and Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
new file mode 100644 (file)
index 0000000..f8c16cb
--- /dev/null
@@ -0,0 +1,24 @@
+1 Release Date    : Mon Jan 23 14:09:01 PST 2006 - Sumant Patro <Sumant.Patro@lsil.com>
+2 Current Version : 00.00.02.02
+3 Older Version   : 00.00.02.01 
+
+i.     New template defined to represent each family of controllers (identified by processor used). 
+       The template will have defintions that will be initialised to appropritae values for a specific family of controllers. The template definition has four function pointers. During driver initialisation the function pointers will be set based on the controller family type. This change is done to support new controllers that has different processors and thus different register set.
+
+               -Sumant Patro <Sumant.Patro@lsil.com>
+
+1 Release Date    : Mon Dec 19 14:36:26 PST 2005 - Sumant Patro <Sumant.Patro@lsil.com>
+2 Current Version : 00.00.02.00-rc4 
+3 Older Version   : 00.00.02.01 
+
+i.     Code reorganized to remove code duplication in megasas_build_cmd. 
+
+       "There's a lot of duplicate code megasas_build_cmd.  Move that out of the different codepathes and merge the reminder of megasas_build_cmd into megasas_queue_command"
+
+               - Christoph Hellwig <hch@lst.de>
+
+ii.    Defined MEGASAS_IOC_FIRMWARE32 for code paths that handles 32 bit applications in 64 bit systems.
+
+       "MEGASAS_IOC_FIRMWARE can't be redefined if CONFIG_COMPAT is set, we need to define a MEGASAS_IOC_FIRMWARE32 define so native binaries continue to work"
+
+               - Christoph Hellwig <hch@lst.de>
index 0aeef740a95a198eddad83113a2a301ac242b801..382b439b439e1ea8c16ee2326e1ab8469884455b 100644 (file)
@@ -1,5 +1,5 @@
 ====================================================================
-=             Adaptec Ultra320 Family Manager Set v1.3.11          =
+=             Adaptec Ultra320 Family Manager Set                  =
 =                                                                  =
 =                            README for                            =
 =                    The Linux Operating System                    =
@@ -63,6 +63,11 @@ The following information is available in this file:
                               68-pin)
 2. Version History
 
+   3.0   (December 1st, 2005)
+       - Updated driver to use SCSI transport class infrastructure
+       - Upported sequencer and core fixes from adaptec released
+         version 2.0.15 of the driver.
+
    1.3.11 (July 11, 2003)
         - Fix several deadlock issues.
         - Add 29320ALP and 39320B Id's.
@@ -194,7 +199,7 @@ The following information is available in this file:
           supported)
         - Support for the PCI-X standard up to 133MHz
         - Support for the PCI v2.2 standard
-       - Domain Validation
+        - Domain Validation
 
    2.2. Operating System Support:
         - Redhat Linux 7.2, 7.3, 8.0, Advanced Server 2.1
@@ -411,77 +416,53 @@ The following information is available in this file:
           http://www.adaptec.com.
 
 
-5. Contacting Adaptec
+5. Adaptec Customer Support
 
    A Technical Support Identification (TSID) Number is required for 
    Adaptec technical support.
     - The 12-digit TSID can be found on the white barcode-type label
-      included inside the box with your product. The TSID helps us 
+      included inside the box with your product.  The TSID helps us 
       provide more efficient service by accurately identifying your 
       product and support status.
+
    Support Options
     - Search the Adaptec Support Knowledgebase (ASK) at
       http://ask.adaptec.com for articles, troubleshooting tips, and
-      frequently asked questions for your product.
+      frequently asked questions about your product.
     - For support via Email, submit your question to Adaptec's 
-      Technical Support Specialists at http://ask.adaptec.com.
+      Technical Support Specialists at http://ask.adaptec.com/.
      
    North America
-    - Visit our Web site at http://www.adaptec.com.
-    - To speak with a Fibre Channel/RAID/External Storage Technical
-      Support Specialist, call 1-321-207-2000,
-      Hours: Monday-Friday, 3:00 A.M. to 5:00 P.M., PST.
-      (Not open on holidays)
-    - For Technical Support in all other technologies including 
-      SCSI, call 1-408-934-7274,
-      Hours: Monday-Friday, 6:00 A.M. to 5:00 P.M., PST.
-      (Not open on holidays)
-    - For after hours support, call 1-800-416-8066 ($99/call, 
-      $149/call on holidays)
-    - To order Adaptec products including software and cables, call
-      1-800-442-7274 or 1-408-957-7274. You can also visit our 
-      online store at http://www.adaptecstore.com
+    - Visit our Web site at http://www.adaptec.com/.
+    - For information about Adaptec's support options, call
+      408-957-2550, 24 hours a day, 7 days a week.
+    - To speak with a Technical Support Specialist,
+      * For hardware products, call 408-934-7274,
+        Monday to Friday, 3:00 am to 5:00 pm, PDT.
+      * For RAID and Fibre Channel products, call 321-207-2000,
+        Monday to Friday, 3:00 am to 5:00 pm, PDT.
+      To expedite your service, have your computer with you.
+    - To order Adaptec products, including accessories and cables,
+      call 408-957-7274.  To order cables online go to
+      http://www.adaptec.com/buy-cables/.
 
    Europe
-    - Visit our Web site at http://www.adaptec-europe.com.
-    - English and French: To speak with a Technical Support 
-      Specialist, call one of the following numbers:
-        - English: +32-2-352-3470
-        - French:  +32-2-352-3460
-      Hours: Monday-Thursday, 10:00 to 12:30, 13:30 to 17:30 CET 
-             Friday, 10:00 to 12:30, 13:30 to 16:30 CET
-    - German: To speak with a Technical Support Specialist,
-      call +49-89-456-40660
-      Hours: Monday-Thursday, 09:30 to 12:30, 13:30 to 16:30 CET
-             Friday, 09:30 to 12:30, 13:30 to 15:00 CET
-    - To order Adaptec products, including accessories and cables:
-        - UK: +0800-96-65-26 or fax +0800-731-02-95
-        - Other European countries: +32-11-300-379
-
-   Australia and New Zealand
-    - Visit our Web site at http://www.adaptec.com.au.
-    - To speak with a Technical Support Specialist, call 
-      +612-9416-0698
-      Hours: Monday-Friday, 10:00 A.M. to 4:30 P.M., EAT
-      (Not open on holidays)
+    - Visit our Web site at http://www.adaptec-europe.com/.
+    - To speak with a Technical Support Specialist, call, or email,
+      * German:  +49 89 4366 5522, Monday-Friday, 9:00-17:00 CET,
+        http://ask-de.adaptec.com/.
+      * French:  +49 89 4366 5533, Monday-Friday, 9:00-17:00 CET,
+       http://ask-fr.adaptec.com/.
+      * English: +49 89 4366 5544, Monday-Friday, 9:00-17:00 GMT,
+       http://ask.adaptec.com/.
+    - You can order Adaptec cables online at
+      http://www.adaptec.com/buy-cables/.
 
    Japan
+    - Visit our web site at http://www.adaptec.co.jp/.
     - To speak with a Technical Support Specialist, call 
-      +81-3-5308-6120 
-      Hours: Monday-Friday, 9:00 a.m. to 12:00 p.m., 1:00 p.m. to
-      6:00 p.m. TSC
-
-   Hong Kong and China
-    - To speak with a Technical Support Specialist, call 
-      +852-2869-7200
-      Hours: Monday-Friday, 10:00 to 17:00.
-    - Fax Technical Support at +852-2869-7100.
-
-   Singapore
-    - To speak with a Technical Support Specialist, call 
-      +65-245-7470
-      Hours: Monday-Friday, 10:00 to 17:00.
-    - Fax Technical Support at +852-2869-7100
+      +81 3 5308 6120, Monday-Friday, 9:00 a.m. to 12:00 p.m.,
+      1:00 p.m. to 6:00 p.m.
 
 -------------------------------------------------------------------
 /*
index 47e74ddc4bc9509b5856b2b8fef0067d6f4eb9d7..3481fcded4c2b5760bb40b79bde4602e369f2115 100644 (file)
@@ -309,81 +309,57 @@ The following information is available in this file:
    -----------------------------------------------------------------
 
    Example:
-   'options aic7xxx aic7xxx=verbose,no_probe,tag_info:{{},{,,10}},seltime:1"
+   'options aic7xxx aic7xxx=verbose,no_probe,tag_info:{{},{,,10}},seltime:1'
         enables verbose logging, Disable EISA/VLB probing,
         and set tag depth on Controller 1/Target 2 to 10 tags.
 
-3. Contacting Adaptec
+4. Adaptec Customer Support
 
    A Technical Support Identification (TSID) Number is required for 
    Adaptec technical support.
     - The 12-digit TSID can be found on the white barcode-type label
-      included inside the box with your product. The TSID helps us 
+      included inside the box with your product.  The TSID helps us 
       provide more efficient service by accurately identifying your 
       product and support status.
+
    Support Options
     - Search the Adaptec Support Knowledgebase (ASK) at
       http://ask.adaptec.com for articles, troubleshooting tips, and
-      frequently asked questions for your product.
+      frequently asked questions about your product.
     - For support via Email, submit your question to Adaptec's 
-      Technical Support Specialists at http://ask.adaptec.com.
+      Technical Support Specialists at http://ask.adaptec.com/.
      
    North America
-    - Visit our Web site at http://www.adaptec.com.
-    - To speak with a Fibre Channel/RAID/External Storage Technical
-      Support Specialist, call 1-321-207-2000,
-      Hours: Monday-Friday, 3:00 A.M. to 5:00 P.M., PST.
-      (Not open on holidays)
-    - For Technical Support in all other technologies including 
-      SCSI, call 1-408-934-7274,
-      Hours: Monday-Friday, 6:00 A.M. to 5:00 P.M., PST.
-      (Not open on holidays)
-    - For after hours support, call 1-800-416-8066 ($99/call, 
-      $149/call on holidays)
-    - To order Adaptec products including software and cables, call
-      1-800-442-7274 or 1-408-957-7274. You can also visit our 
-      online store at http://www.adaptecstore.com
+    - Visit our Web site at http://www.adaptec.com/.
+    - For information about Adaptec's support options, call
+      408-957-2550, 24 hours a day, 7 days a week.
+    - To speak with a Technical Support Specialist,
+      * For hardware products, call 408-934-7274,
+        Monday to Friday, 3:00 am to 5:00 pm, PDT.
+      * For RAID and Fibre Channel products, call 321-207-2000,
+        Monday to Friday, 3:00 am to 5:00 pm, PDT.
+      To expedite your service, have your computer with you.
+    - To order Adaptec products, including accessories and cables,
+      call 408-957-7274.  To order cables online go to
+      http://www.adaptec.com/buy-cables/.
 
    Europe
-    - Visit our Web site at http://www.adaptec-europe.com.
-    - English and French: To speak with a Technical Support 
-      Specialist, call one of the following numbers:
-        - English: +32-2-352-3470
-        - French:  +32-2-352-3460
-      Hours: Monday-Thursday, 10:00 to 12:30, 13:30 to 17:30 CET 
-             Friday, 10:00 to 12:30, 13:30 to 16:30 CET
-    - German: To speak with a Technical Support Specialist,
-      call +49-89-456-40660
-      Hours: Monday-Thursday, 09:30 to 12:30, 13:30 to 16:30 CET
-             Friday, 09:30 to 12:30, 13:30 to 15:00 CET
-    - To order Adaptec products, including accessories and cables:
-        - UK: +0800-96-65-26 or fax +0800-731-02-95
-        - Other European countries: +32-11-300-379
-
-   Australia and New Zealand
-    - Visit our Web site at http://www.adaptec.com.au.
-    - To speak with a Technical Support Specialist, call 
-      +612-9416-0698
-      Hours: Monday-Friday, 10:00 A.M. to 4:30 P.M., EAT
-      (Not open on holidays)
+    - Visit our Web site at http://www.adaptec-europe.com/.
+    - To speak with a Technical Support Specialist, call, or email,
+      * German:  +49 89 4366 5522, Monday-Friday, 9:00-17:00 CET,
+        http://ask-de.adaptec.com/.
+      * French:  +49 89 4366 5533, Monday-Friday, 9:00-17:00 CET,
+       http://ask-fr.adaptec.com/.
+      * English: +49 89 4366 5544, Monday-Friday, 9:00-17:00 GMT,
+       http://ask.adaptec.com/.
+    - You can order Adaptec cables online at
+      http://www.adaptec.com/buy-cables/.
 
    Japan
+    - Visit our web site at http://www.adaptec.co.jp/.
     - To speak with a Technical Support Specialist, call 
-      +81-3-5308-6120 
-      Hours: Monday-Friday, 9:00 a.m. to 12:00 p.m., 1:00 p.m. to
-      6:00 p.m. TSC
-
-   Hong Kong and China
-    - To speak with a Technical Support Specialist, call 
-      +852-2869-7200
-      Hours: Monday-Friday, 10:00 to 17:00.
-    - Fax Technical Support at +852-2869-7100.
-
-   Singapore
-    - To speak with a Technical Support Specialist, call 
-      +65-245-7470
-      Hours: Monday-Friday, 10:00 to 17:00.
-    - Fax Technical Support at +852-2869-7100
+      +81 3 5308 6120, Monday-Friday, 9:00 a.m. to 12:00 p.m.,
+      1:00 p.m. to 6:00 p.m.
 
 -------------------------------------------------------------------
 /*
diff --git a/Documentation/usb/et61x251.txt b/Documentation/usb/et61x251.txt
new file mode 100644 (file)
index 0000000..b44dda4
--- /dev/null
@@ -0,0 +1,306 @@
+
+                       ET61X[12]51 PC Camera Controllers
+                                Driver for Linux
+                       =================================
+
+                               - Documentation -
+
+
+Index
+=====
+1.  Copyright
+2.  Disclaimer
+3.  License
+4.  Overview and features
+5.  Module dependencies
+6.  Module loading
+7.  Module parameters
+8.  Optional device control through "sysfs"
+9.  Supported devices
+10. Notes for V4L2 application developers
+11. Contact information
+
+
+1. Copyright
+============
+Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>
+
+
+2. Disclaimer
+=============
+Etoms is a trademark of Etoms Electronics Corp.
+This software is not developed or sponsored by Etoms Electronics.
+
+
+3. License
+==========
+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.
+
+
+4. Overview and features
+========================
+This driver supports the video interface of the devices mounting the ET61X151
+or ET61X251 PC Camera Controllers.
+
+It's worth to note that Etoms Electronics has never collaborated with the
+author during the development of this project; despite several requests,
+Etoms Electronics also refused to release enough detailed specifications of
+the video compression engine.
+
+The driver relies on the Video4Linux2 and USB core modules. It has been
+designed to run properly on SMP systems as well.
+
+The latest version of the ET61X[12]51 driver can be found at the following URL:
+http://www.linux-projects.org/
+
+Some of the features of the driver are:
+
+- full compliance with the Video4Linux2 API (see also "Notes for V4L2
+  application developers" paragraph);
+- available mmap or read/poll methods for video streaming through isochronous
+  data transfers;
+- automatic detection of image sensor;
+- support for any window resolutions and optional panning within the maximum
+  pixel area of image sensor;
+- image downscaling with arbitrary scaling factors from 1 and 2 in both
+  directions (see "Notes for V4L2 application developers" paragraph);
+- two different video formats for uncompressed or compressed data in low or
+  high compression quality (see also "Notes for V4L2 application developers"
+  paragraph);
+- full support for the capabilities of every possible image sensors that can
+  be connected to the ET61X[12]51 bridges, including, for istance, red, green,
+  blue and global gain adjustments and exposure control (see "Supported
+  devices" paragraph for details);
+- use of default color settings for sunlight conditions;
+- dynamic I/O interface for both ET61X[12]51 and image sensor control (see
+  "Optional device control through 'sysfs'" paragraph);
+- dynamic driver control thanks to various module parameters (see "Module
+  parameters" paragraph);
+- up to 64 cameras can be handled at the same time; they can be connected and
+  disconnected from the host many times without turning off the computer, if
+  the system supports hotplugging;
+- no known bugs.
+
+
+5. Module dependencies
+======================
+For it to work properly, the driver needs kernel support for Video4Linux and
+USB.
+
+The following options of the kernel configuration file must be enabled and
+corresponding modules must be compiled:
+
+       # Multimedia devices
+       #
+       CONFIG_VIDEO_DEV=m
+
+To enable advanced debugging functionality on the device through /sysfs:
+
+       # Multimedia devices
+       #
+       CONFIG_VIDEO_ADV_DEBUG=y
+
+       # USB support
+       #
+       CONFIG_USB=m
+
+In addition, depending on the hardware being used, the modules below are
+necessary:
+
+       # USB Host Controller Drivers
+       #
+       CONFIG_USB_EHCI_HCD=m
+       CONFIG_USB_UHCI_HCD=m
+       CONFIG_USB_OHCI_HCD=m
+
+And finally:
+
+       # USB Multimedia devices
+       #
+       CONFIG_USB_ET61X251=m
+
+
+6. Module loading
+=================
+To use the driver, it is necessary to load the "et61x251" module into memory
+after every other module required: "videodev", "usbcore" and, depending on
+the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
+
+Loading can be done as shown below:
+
+       [root@localhost home]# modprobe et61x251
+
+At this point the devices should be recognized. You can invoke "dmesg" to
+analyze kernel messages and verify that the loading process has gone well:
+
+       [user@localhost home]$ dmesg
+
+
+7. Module parameters
+====================
+Module parameters are listed below:
+-------------------------------------------------------------------------------
+Name:           video_nr
+Type:           short array (min = 0, max = 64)
+Syntax:         <-1|n[,...]>
+Description:    Specify V4L2 minor mode number:
+                -1 = use next available
+                 n = use minor number n
+                You can specify up to 64 cameras this way.
+                For example:
+                video_nr=-1,2,-1 would assign minor number 2 to the second
+                registered camera and use auto for the first one and for every
+                other camera.
+Default:        -1
+-------------------------------------------------------------------------------
+Name:           force_munmap
+Type:           bool array (min = 0, max = 64)
+Syntax:         <0|1[,...]>
+Description:    Force the application to unmap previously mapped buffer memory
+                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+                all the applications support this feature. This parameter is
+                specific for each detected camera.
+                0 = do not force memory unmapping
+                1 = force memory unmapping (save memory)
+Default:        0
+-------------------------------------------------------------------------------
+Name:           debug
+Type:           ushort
+Syntax:         <n>
+Description:    Debugging information level, from 0 to 3:
+                0 = none (use carefully)
+                1 = critical errors
+                2 = significant informations
+                3 = more verbose messages
+                Level 3 is useful for testing only, when only one device
+                is used at the same time. It also shows some more informations
+                about the hardware being detected. This module parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
+
+
+8. Optional device control through "sysfs"
+==========================================
+If the kernel has been compiled with the CONFIG_VIDEO_ADV_DEBUG option enabled,
+it is possible to read and write both the ET61X[12]51 and the image sensor
+registers by using the "sysfs" filesystem interface.
+
+There are four files in the /sys/class/video4linux/videoX directory for each
+registered camera: "reg", "val", "i2c_reg" and "i2c_val". The first two files
+control the ET61X[12]51 bridge, while the other two control the sensor chip.
+"reg" and "i2c_reg" hold the values of the current register index where the
+following reading/writing operations are addressed at through "val" and
+"i2c_val". Their use is not intended for end-users, unless you know what you
+are doing. Remember that you must be logged in as root before writing to them.
+
+As an example, suppose we were to want to read the value contained in the
+register number 1 of the sensor register table - which is usually the product
+identifier - of the camera registered as "/dev/video0":
+
+       [root@localhost #] cd /sys/class/video4linux/video0
+       [root@localhost #] echo 1 > i2c_reg
+       [root@localhost #] cat i2c_val
+
+Note that if the sensor registers can not be read, "cat" will fail.
+To avoid race conditions, all the I/O accesses to the files are serialized.
+
+
+9. Supported devices
+====================
+None of the names of the companies as well as their products will be mentioned
+here. They have never collaborated with the author, so no advertising.
+
+From the point of view of a driver, what unambiguously identify a device are
+its vendor and product USB identifiers. Below is a list of known identifiers of
+devices mounting the ET61X[12]51 PC camera controllers:
+
+Vendor ID  Product ID
+---------  ----------
+0x102c     0x6151
+0x102c     0x6251
+0x102c     0x6253
+0x102c     0x6254
+0x102c     0x6255
+0x102c     0x6256
+0x102c     0x6257
+0x102c     0x6258
+0x102c     0x6259
+0x102c     0x625a
+0x102c     0x625b
+0x102c     0x625c
+0x102c     0x625d
+0x102c     0x625e
+0x102c     0x625f
+0x102c     0x6260
+0x102c     0x6261
+0x102c     0x6262
+0x102c     0x6263
+0x102c     0x6264
+0x102c     0x6265
+0x102c     0x6266
+0x102c     0x6267
+0x102c     0x6268
+0x102c     0x6269
+
+The following image sensors are supported:
+
+Model       Manufacturer
+-----       ------------
+TAS5130D1B  Taiwan Advanced Sensor Corporation
+
+All the available control settings of each image sensor are supported through
+the V4L2 interface.
+
+
+10. Notes for V4L2 application developers
+========================================
+This driver follows the V4L2 API specifications. In particular, it enforces two
+rules:
+
+- exactly one I/O method, either "mmap" or "read", is associated with each
+file descriptor. Once it is selected, the application must close and reopen the
+device to switch to the other I/O method;
+
+- although it is not mandatory, previously mapped buffer memory should always
+be unmapped before calling any "VIDIOC_S_CROP" or "VIDIOC_S_FMT" ioctl's.
+The same number of buffers as before will be allocated again to match the size
+of the new video frames, so you have to map the buffers again before any I/O
+attempts on them.
+
+Consistently with the hardware limits, this driver also supports image
+downscaling with arbitrary scaling factors from 1 and 2 in both directions.
+However, the V4L2 API specifications don't correctly define how the scaling
+factor can be chosen arbitrarily by the "negotiation" of the "source" and
+"target" rectangles. To work around this flaw, we have added the convention
+that, during the negotiation, whenever the "VIDIOC_S_CROP" ioctl is issued, the
+scaling factor is restored to 1.
+
+This driver supports two different video formats: the first one is the "8-bit
+Sequential Bayer" format and can be used to obtain uncompressed video data
+from the device through the current I/O method, while the second one provides
+"raw" compressed video data (without frame headers not related to the
+compressed data). The current compression quality may vary from 0 to 1 and can
+be selected or queried thanks to the VIDIOC_S_JPEGCOMP and VIDIOC_G_JPEGCOMP
+V4L2 ioctl's.
+
+
+11. Contact information
+=======================
+The author may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
+
+GPG/PGP encrypted e-mail's are accepted. The GPG key ID of the author is
+'FCE635A4'; the public 1024-bit key should be available at any keyserver;
+the fingerprint is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
index 3f8a119db31b3018ad30da389bbc065eb7a35983..c6b76414172cd74455103acbec763b2e49882b90 100644 (file)
@@ -17,16 +17,15 @@ Index
 7.  Module parameters
 8.  Optional device control through "sysfs"
 9.  Supported devices
-10. How to add plug-in's for new image sensors
-11. Notes for V4L2 application developers
-12. Video frame formats
-13. Contact information
-14. Credits
+10. Notes for V4L2 application developers
+11. Video frame formats
+12. Contact information
+13. Credits
 
 
 1. Copyright
 ============
-Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>
+Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>
 
 
 2. Disclaimer
@@ -54,9 +53,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 4. Overview and features
 ========================
-This driver attempts to support the video and audio streaming capabilities of
-the devices mounting the SONiX SN9C101, SN9C102 and SN9C103 PC Camera
-Controllers.
+This driver attempts to support the video interface of the devices mounting the
+SONiX SN9C101, SN9C102 and SN9C103 PC Camera Controllers.
 
 It's worth to note that SONiX has never collaborated with the author during the
 development of this project, despite several requests for enough detailed
@@ -78,6 +76,7 @@ Some of the features of the driver are:
 - available mmap or read/poll methods for video streaming through isochronous
   data transfers;
 - automatic detection of image sensor;
+- support for built-in microphone interface;
 - support for any window resolutions and optional panning within the maximum
   pixel area of image sensor;
 - image downscaling with arbitrary scaling factors from 1, 2 and 4 in both
@@ -96,7 +95,7 @@ Some of the features of the driver are:
   parameters" paragraph);
 - up to 64 cameras can be handled at the same time; they can be connected and
   disconnected from the host many times without turning off the computer, if
-  your system supports hotplugging;
+  the system supports hotplugging;
 - no known bugs.
 
 
@@ -112,6 +111,12 @@ corresponding modules must be compiled:
        #
        CONFIG_VIDEO_DEV=m
 
+To enable advanced debugging functionality on the device through /sysfs:
+
+       # Multimedia devices
+       #
+       CONFIG_VIDEO_ADV_DEBUG=y
+
        # USB support
        #
        CONFIG_USB=m
@@ -125,6 +130,21 @@ necessary:
        CONFIG_USB_UHCI_HCD=m
        CONFIG_USB_OHCI_HCD=m
 
+The SN9C103 controller also provides a built-in microphone interface. It is
+supported by the USB Audio driver thanks to the ALSA API:
+
+       # Sound
+       #
+       CONFIG_SOUND=y
+
+       # Advanced Linux Sound Architecture
+       #
+       CONFIG_SND=m
+
+       # USB devices
+       #
+       CONFIG_SND_USB_AUDIO=m
+
 And finally:
 
        # USB Multimedia devices
@@ -153,7 +173,7 @@ analyze kernel messages and verify that the loading process has gone well:
 Module parameters are listed below:
 -------------------------------------------------------------------------------
 Name:           video_nr
-Type:           int array (min = 0, max = 64)
+Type:           short array (min = 0, max = 64)
 Syntax:         <-1|n[,...]> 
 Description:    Specify V4L2 minor mode number:
                 -1 = use next available
@@ -165,19 +185,19 @@ Description:    Specify V4L2 minor mode number:
                 other camera.
 Default:        -1
 -------------------------------------------------------------------------------
-Name:           force_munmap;
+Name:           force_munmap
 Type:           bool array (min = 0, max = 64)
 Syntax:         <0|1[,...]> 
 Description:    Force the application to unmap previously mapped buffer memory
                 before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
                 all the applications support this feature. This parameter is
                 specific for each detected camera.
-                0 = do not force memory unmapping"
-                1 = force memory unmapping (save memory)"
+                0 = do not force memory unmapping
+                1 = force memory unmapping (save memory)
 Default:        0
 -------------------------------------------------------------------------------
 Name:           debug
-Type:           int
+Type:           ushort
 Syntax:         <n> 
 Description:    Debugging information level, from 0 to 3:
                 0 = none (use carefully)
@@ -187,14 +207,15 @@ Description:    Debugging information level, from 0 to 3:
                 Level 3 is useful for testing only, when only one device
                 is used. It also shows some more informations about the
                 hardware being detected. This parameter can be changed at
-                runtime thanks to the /sys filesystem.
+                runtime thanks to the /sys filesystem interface.
 Default:        2
 -------------------------------------------------------------------------------
 
 
 8. Optional device control through "sysfs" [1]
 ==========================================
-It is possible to read and write both the SN9C10x and the image sensor
+If the kernel has been compiled with the CONFIG_VIDEO_ADV_DEBUG option enabled,
+it is possible to read and write both the SN9C10x and the image sensor
 registers by using the "sysfs" filesystem interface.
 
 Every time a supported device is recognized, a write-only file named "green" is
@@ -236,7 +257,7 @@ serialized.
 
 The sysfs interface also provides the "frame_header" entry, which exports the
 frame header of the most recent requested and captured video frame. The header
-is 12-bytes long and is appended to every video frame by the SN9C10x
+is always 18-bytes long and is appended to every video frame by the SN9C10x
 controllers. As an example, this additional information can be used by the user
 application for implementing auto-exposure features via software. 
 
@@ -250,7 +271,8 @@ Byte #  Value         Description
 0x03    0xC4          Frame synchronisation pattern.
 0x04    0xC4          Frame synchronisation pattern.
 0x05    0x96          Frame synchronisation pattern.
-0x06    0x00 or 0x01  Unknown meaning. The exact value depends on the chip.
+0x06    0xXX          Unknown meaning. The exact value depends on the chip;
+                      possible values are 0x00, 0x01 and 0x20.
 0x07    0xXX          Variable value, whose bits are ff00uzzc, where ff is a
                       frame counter, u is unknown, zz is a size indicator
                       (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
@@ -267,12 +289,23 @@ Byte #  Value         Description
                       times the area outside of the specified AE area. For
                       images that are not pure white, the value scales down
                       according to relative whiteness.
+                      according to relative whiteness.
+
+The following bytes are used by the SN9C103 bridge only:
+
+0x0C    0xXX          Unknown meaning
+0x0D    0xXX          Unknown meaning
+0x0E    0xXX          Unknown meaning
+0x0F    0xXX          Unknown meaning
+0x10    0xXX          Unknown meaning
+0x11    0xXX          Unknown meaning
 
 The AE area (sx, sy, ex, ey) in the active window can be set by programming the
 registers 0x1c, 0x1d, 0x1e and 0x1f of the SN9C10x controllers, where one unit
 corresponds to 32 pixels.
 
-[1] The frame header has been documented by Bertrik Sikken.
+[1] Part of the meaning of the frame header has been documented by Bertrik
+    Sikken.
 
 
 9. Supported devices
@@ -298,6 +331,7 @@ Vendor ID  Product ID
 0x0c45     0x602b
 0x0c45     0x602c
 0x0c45     0x602d
+0x0c45     0x602e
 0x0c45     0x6030
 0x0c45     0x6080
 0x0c45     0x6082
@@ -348,18 +382,7 @@ appreciated. Non-available hardware will not be supported by the author of this
 driver.
 
 
-10. How to add plug-in's for new image sensors
-==============================================
-It should be easy to write plug-in's for new sensors by using the small API
-that has been created for this purpose, which is present in "sn9c102_sensor.h"
-(documentation is included there). As an example, have a look at the code in
-"sn9c102_pas106b.c", which uses the mentioned interface.
-
-At the moment, possible unsupported image sensors are: CIS-VF10 (VGA),
-OV7620 (VGA), OV7630 (VGA).
-
-
-11. Notes for V4L2 application developers
+10. Notes for V4L2 application developers
 =========================================
 This driver follows the V4L2 API specifications. In particular, it enforces two
 rules:
@@ -394,7 +417,7 @@ initialized (as described in the documentation of the API for the image sensors
 supplied by this driver).
 
 
-12. Video frame formats [1]
+11. Video frame formats [1]
 =======================
 The SN9C10x PC Camera Controllers can send images in two possible video
 formats over the USB: either native "Sequential RGB Bayer" or Huffman
@@ -455,7 +478,7 @@ The following Huffman codes have been found:
     documented by Bertrik Sikken.
 
 
-13. Contact information
+12. Contact information
 =======================
 The author may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
 
@@ -464,7 +487,7 @@ GPG/PGP encrypted e-mail's are accepted. The GPG key ID of the author is
 the fingerprint is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
 
 
-14. Credits
+13. Credits
 ===========
 Many thanks to following persons for their contribute (listed in alphabetical
 order):
@@ -480,5 +503,5 @@ order):
 - Bertrik Sikken, who reverse-engineered and documented the Huffman compression
   algorithm used in the SN9C10x controllers and implemented the first decoder;
 - Mizuno Takafumi for the donation of a webcam;
-- An "anonymous" donator (who didn't want his name to be revealed) for the
+- an "anonymous" donator (who didn't want his name to be revealed) for the
   donation of a webcam.
index 18a47738d56c075c4ca37f6f724f3ca8d37401de..9d46cd0b19e3190064da339dbe108b3184e1c7f0 100644 (file)
@@ -57,16 +57,12 @@ based cameras should be supported as well.
 The driver is divided into two modules: the basic one, "w9968cf", is needed for
 the supported devices to work; the second one, "w9968cf-vpp", is an optional
 module, which provides some useful video post-processing functions like video
-decoding, up-scaling and colour conversions. Once the driver is installed,
-every time an application tries to open a recognized device, "w9968cf" checks
-the presence of the "w9968cf-vpp" module and loads it automatically by default.
+decoding, up-scaling and colour conversions.
 
-Please keep in mind that official kernels do not include the second module for
-performance purposes. However it is always recommended to download and install
-the latest and complete release of the driver, replacing the existing one, if
-present: it will be still even possible not to load the "w9968cf-vpp" module at
-all, if you ever want to. Another important missing feature of the version in
-the official Linux 2.4 kernels is the writeable /proc filesystem interface.
+Note that the official kernels do neither include nor support the second
+module for performance purposes. Therefore, it is always recommended to
+download and install the latest and complete release of the driver,
+replacing the existing one, if present.
 
 The latest and full-featured version of the W996[87]CF driver can be found at:
 http://www.linux-projects.org. Please refer to the documentation included in
@@ -201,22 +197,6 @@ Note:            The kernel must be compiled with the CONFIG_KMOD option
                  enabled for the 'ovcamchip' module to be loaded and for
                  this parameter to be present.
 -------------------------------------------------------------------------------
-Name:           vppmod_load
-Type:           bool
-Syntax:         <0|1>
-Description:    Automatic 'w9968cf-vpp' module loading: 0 disabled, 1 enabled.
-                If enabled, every time an application attempts to open a
-                camera, 'insmod' searches for the video post-processing module
-                in the system and loads it automatically (if present).
-                The optional 'w9968cf-vpp' module adds extra image manipulation
-                capabilities to the 'w9968cf' module,like software up-scaling,
-                colour conversions and video decompression for very high frame
-                rates.
-Default:        1
-Note:           The kernel must be compiled with the CONFIG_KMOD option
-                enabled for the 'w9968cf-vpp' module to be loaded and for
-                this parameter to be present.
--------------------------------------------------------------------------------
 Name:           simcams 
 Type:           int 
 Syntax:         <n> 
index 3f8a90ac47d7942d81f20ab9b3aa0f14056d8e88..42955fe1ffa056df2f412280b7d9e45a17060d31 100644 (file)
@@ -1176,8 +1176,8 @@ T:        git kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
 S:     Maintained
 
 SN-IA64 (Itanium) SUB-PLATFORM
-P:     Greg Edwards
-M:     edwardsg@sgi.com
+P:     Jes Sorensen
+M:     jes@sgi.com
 L:     linux-altix@sgi.com
 L:     linux-ia64@vger.kernel.org
 W:     http://www.sgi.com/altix
@@ -2673,6 +2673,14 @@ M:       dbrownell@users.sourceforge.net
 L:     linux-usb-devel@lists.sourceforge.net
 S:     Maintained
 
+USB ET61X[12]51 DRIVER
+P:     Luca Risolia
+M:     luca.risolia@studio.unibo.it
+L:     linux-usb-devel@lists.sourceforge.net
+L:     video4linux-list@redhat.com
+W:     http://www.linux-projects.org
+S:     Maintained
+
 USB HID/HIDBP DRIVERS
 P:     Vojtech Pavlik
 M:     vojtech@suse.cz
@@ -2836,6 +2844,7 @@ USB SN9C10x DRIVER
 P:     Luca Risolia
 M:     luca.risolia@studio.unibo.it
 L:     linux-usb-devel@lists.sourceforge.net
+L:     video4linux-list@redhat.com
 W:     http://www.linux-projects.org
 S:     Maintained
 
@@ -2865,6 +2874,7 @@ USB W996[87]CF DRIVER
 P:     Luca Risolia
 M:     luca.risolia@studio.unibo.it
 L:     linux-usb-devel@lists.sourceforge.net
+L:     video4linux-list@redhat.com
 W:     http://www.linux-projects.org
 S:     Maintained
 
index 6886001b53666acc69f1adc802e73b7c8883446f..4a8564f386af9e42f575c6b07199225704507ca1 100644 (file)
@@ -14,8 +14,7 @@ CONFIG_GENERIC_IOMAP=y
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
+CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
@@ -360,7 +359,6 @@ CONFIG_BLK_DEV_IDE_BAST=y
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
@@ -781,7 +779,6 @@ CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
-# CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
index 15468a0cf70e8de3583c2ad531f34e1a8992e884..c9aa878e610acd0fe9a7736456515113149987ce 100644 (file)
@@ -13,8 +13,7 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
+CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
@@ -308,9 +307,7 @@ CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
 CONFIG_MTD_OBSOLETE_CHIPS=y
-# CONFIG_MTD_AMDSTD is not set
 CONFIG_MTD_SHARP=y
-# CONFIG_MTD_JEDEC is not set
 
 #
 # Mapping drivers for chip access
@@ -396,7 +393,6 @@ CONFIG_ATA_OVER_ETH=m
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
@@ -741,7 +737,6 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 CONFIG_PROC_FS=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
index 33f31080a98c4e0a54833f324d498beaf72ce13f..1964ccd8a71f7fbd9a039fe2982d590e9c132d89 100644 (file)
@@ -13,8 +13,7 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
+CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 
@@ -473,7 +472,6 @@ CONFIG_BLK_DEV_IDE_BAST=y
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
@@ -896,7 +894,6 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 CONFIG_PROC_FS=y
 CONFIG_SYSFS=y
 # CONFIG_TMPFS is not set
-# CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 # CONFIG_RELAYFS_FS is not set
index 75e6f9a947133b5d2768cf8aa9ab73f1488e3625..d058e7c125681bccc28228f225d22525306925a7 100644 (file)
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  This file is included twice in entry-common.S
+ *  This file is included thrice in entry-common.S
  */
-#ifndef NR_syscalls
-#define NR_syscalls 328
-#else
-
-100:
-/* 0 */                .long   sys_restart_syscall
-               .long   sys_exit
-               .long   sys_fork_wrapper
-               .long   sys_read
-               .long   sys_write
-/* 5 */                .long   sys_open
-               .long   sys_close
-               .long   sys_ni_syscall          /* was sys_waitpid */
-               .long   sys_creat
-               .long   sys_link
-/* 10 */       .long   sys_unlink
-               .long   sys_execve_wrapper
-               .long   sys_chdir
-               .long   OBSOLETE(sys_time)      /* used by libc4 */
-               .long   sys_mknod
-/* 15 */       .long   sys_chmod
-               .long   sys_lchown16
-               .long   sys_ni_syscall          /* was sys_break */
-               .long   sys_ni_syscall          /* was sys_stat */
-               .long   sys_lseek
-/* 20 */       .long   sys_getpid
-               .long   sys_mount
-               .long   OBSOLETE(sys_oldumount) /* used by libc4 */
-               .long   sys_setuid16
-               .long   sys_getuid16
-/* 25 */       .long   OBSOLETE(sys_stime)
-               .long   sys_ptrace
-               .long   OBSOLETE(sys_alarm)     /* used by libc4 */
-               .long   sys_ni_syscall          /* was sys_fstat */
-               .long   sys_pause
-/* 30 */       .long   OBSOLETE(sys_utime)     /* used by libc4 */
-               .long   sys_ni_syscall          /* was sys_stty */
-               .long   sys_ni_syscall          /* was sys_getty */
-               .long   sys_access
-               .long   sys_nice
-/* 35 */       .long   sys_ni_syscall          /* was sys_ftime */
-               .long   sys_sync
-               .long   sys_kill
-               .long   sys_rename
-               .long   sys_mkdir
-/* 40 */       .long   sys_rmdir
-               .long   sys_dup
-               .long   sys_pipe
-               .long   sys_times
-               .long   sys_ni_syscall          /* was sys_prof */
-/* 45 */       .long   sys_brk
-               .long   sys_setgid16
-               .long   sys_getgid16
-               .long   sys_ni_syscall          /* was sys_signal */
-               .long   sys_geteuid16
-/* 50 */       .long   sys_getegid16
-               .long   sys_acct
-               .long   sys_umount
-               .long   sys_ni_syscall          /* was sys_lock */
-               .long   sys_ioctl
-/* 55 */       .long   sys_fcntl
-               .long   sys_ni_syscall          /* was sys_mpx */
-               .long   sys_setpgid
-               .long   sys_ni_syscall          /* was sys_ulimit */
-               .long   sys_ni_syscall          /* was sys_olduname */
-/* 60 */       .long   sys_umask
-               .long   sys_chroot
-               .long   sys_ustat
-               .long   sys_dup2
-               .long   sys_getppid
-/* 65 */       .long   sys_getpgrp
-               .long   sys_setsid
-               .long   sys_sigaction
-               .long   sys_ni_syscall          /* was sys_sgetmask */
-               .long   sys_ni_syscall          /* was sys_ssetmask */
-/* 70 */       .long   sys_setreuid16
-               .long   sys_setregid16
-               .long   sys_sigsuspend_wrapper
-               .long   sys_sigpending
-               .long   sys_sethostname
-/* 75 */       .long   sys_setrlimit
-               .long   OBSOLETE(sys_old_getrlimit) /* used by libc4 */
-               .long   sys_getrusage
-               .long   sys_gettimeofday
-               .long   sys_settimeofday
-/* 80 */       .long   sys_getgroups16
-               .long   sys_setgroups16
-               .long   OBSOLETE(old_select)    /* used by libc4 */
-               .long   sys_symlink
-               .long   sys_ni_syscall          /* was sys_lstat */
-/* 85 */       .long   sys_readlink
-               .long   sys_uselib
-               .long   sys_swapon
-               .long   sys_reboot
-               .long   OBSOLETE(old_readdir)   /* used by libc4 */
-/* 90 */       .long   OBSOLETE(old_mmap)      /* used by libc4 */
-               .long   sys_munmap
-               .long   sys_truncate
-               .long   sys_ftruncate
-               .long   sys_fchmod
-/* 95 */       .long   sys_fchown16
-               .long   sys_getpriority
-               .long   sys_setpriority
-               .long   sys_ni_syscall          /* was sys_profil */
-               .long   sys_statfs
-/* 100 */      .long   sys_fstatfs
-               .long   sys_ni_syscall
-               .long   OBSOLETE(sys_socketcall)
-               .long   sys_syslog
-               .long   sys_setitimer
-/* 105 */      .long   sys_getitimer
-               .long   sys_newstat
-               .long   sys_newlstat
-               .long   sys_newfstat
-               .long   sys_ni_syscall          /* was sys_uname */
-/* 110 */      .long   sys_ni_syscall          /* was sys_iopl */
-               .long   sys_vhangup
-               .long   sys_ni_syscall
-               .long   OBSOLETE(sys_syscall)   /* call a syscall */
-               .long   sys_wait4
-/* 115 */      .long   sys_swapoff
-               .long   sys_sysinfo
-               .long   OBSOLETE(ABI(sys_ipc, sys_oabi_ipc))
-               .long   sys_fsync
-               .long   sys_sigreturn_wrapper
-/* 120 */      .long   sys_clone_wrapper
-               .long   sys_setdomainname
-               .long   sys_newuname
-               .long   sys_ni_syscall
-               .long   sys_adjtimex
-/* 125 */      .long   sys_mprotect
-               .long   sys_sigprocmask
-               .long   sys_ni_syscall          /* was sys_create_module */
-               .long   sys_init_module
-               .long   sys_delete_module
-/* 130 */      .long   sys_ni_syscall          /* was sys_get_kernel_syms */
-               .long   sys_quotactl
-               .long   sys_getpgid
-               .long   sys_fchdir
-               .long   sys_bdflush
-/* 135 */      .long   sys_sysfs
-               .long   sys_personality
-               .long   sys_ni_syscall          /* .long        _sys_afs_syscall */
-               .long   sys_setfsuid16
-               .long   sys_setfsgid16
-/* 140 */      .long   sys_llseek
-               .long   sys_getdents
-               .long   sys_select
-               .long   sys_flock
-               .long   sys_msync
-/* 145 */      .long   sys_readv
-               .long   sys_writev
-               .long   sys_getsid
-               .long   sys_fdatasync
-               .long   sys_sysctl
-/* 150 */      .long   sys_mlock
-               .long   sys_munlock
-               .long   sys_mlockall
-               .long   sys_munlockall
-               .long   sys_sched_setparam
-/* 155 */      .long   sys_sched_getparam
-               .long   sys_sched_setscheduler
-               .long   sys_sched_getscheduler
-               .long   sys_sched_yield
-               .long   sys_sched_get_priority_max
-/* 160 */      .long   sys_sched_get_priority_min
-               .long   sys_sched_rr_get_interval
-               .long   sys_nanosleep
-               .long   sys_arm_mremap
-               .long   sys_setresuid16
-/* 165 */      .long   sys_getresuid16
-               .long   sys_ni_syscall
-               .long   sys_ni_syscall          /* was sys_query_module */
-               .long   sys_poll
-               .long   sys_nfsservctl
-/* 170 */      .long   sys_setresgid16
-               .long   sys_getresgid16
-               .long   sys_prctl
-               .long   sys_rt_sigreturn_wrapper
-               .long   sys_rt_sigaction
-/* 175 */      .long   sys_rt_sigprocmask
-               .long   sys_rt_sigpending
-               .long   sys_rt_sigtimedwait
-               .long   sys_rt_sigqueueinfo
-               .long   sys_rt_sigsuspend_wrapper
-/* 180 */      .long   ABI(sys_pread64, sys_oabi_pread64)
-               .long   ABI(sys_pwrite64, sys_oabi_pwrite64)
-               .long   sys_chown16
-               .long   sys_getcwd
-               .long   sys_capget
-/* 185 */      .long   sys_capset
-               .long   sys_sigaltstack_wrapper
-               .long   sys_sendfile
-               .long   sys_ni_syscall
-               .long   sys_ni_syscall
-/* 190 */      .long   sys_vfork_wrapper
-               .long   sys_getrlimit
-               .long   sys_mmap2
-               .long   ABI(sys_truncate64, sys_oabi_truncate64)
-               .long   ABI(sys_ftruncate64, sys_oabi_ftruncate64)
-/* 195 */      .long   ABI(sys_stat64, sys_oabi_stat64)
-               .long   ABI(sys_lstat64, sys_oabi_lstat64)
-               .long   ABI(sys_fstat64, sys_oabi_fstat64)
-               .long   sys_lchown
-               .long   sys_getuid
-/* 200 */      .long   sys_getgid
-               .long   sys_geteuid
-               .long   sys_getegid
-               .long   sys_setreuid
-               .long   sys_setregid
-/* 205 */      .long   sys_getgroups
-               .long   sys_setgroups
-               .long   sys_fchown
-               .long   sys_setresuid
-               .long   sys_getresuid
-/* 210 */      .long   sys_setresgid
-               .long   sys_getresgid
-               .long   sys_chown
-               .long   sys_setuid
-               .long   sys_setgid
-/* 215 */      .long   sys_setfsuid
-               .long   sys_setfsgid
-               .long   sys_getdents64
-               .long   sys_pivot_root
-               .long   sys_mincore
-/* 220 */      .long   sys_madvise
-               .long   ABI(sys_fcntl64, sys_oabi_fcntl64)
-               .long   sys_ni_syscall /* TUX */
-               .long   sys_ni_syscall
-               .long   sys_gettid
-/* 225 */      .long   ABI(sys_readahead, sys_oabi_readahead)
-               .long   sys_setxattr
-               .long   sys_lsetxattr
-               .long   sys_fsetxattr
-               .long   sys_getxattr
-/* 230 */      .long   sys_lgetxattr
-               .long   sys_fgetxattr
-               .long   sys_listxattr
-               .long   sys_llistxattr
-               .long   sys_flistxattr
-/* 235 */      .long   sys_removexattr
-               .long   sys_lremovexattr
-               .long   sys_fremovexattr
-               .long   sys_tkill
-               .long   sys_sendfile64
-/* 240 */      .long   sys_futex
-               .long   sys_sched_setaffinity
-               .long   sys_sched_getaffinity
-               .long   sys_io_setup
-               .long   sys_io_destroy
-/* 245 */      .long   sys_io_getevents
-               .long   sys_io_submit
-               .long   sys_io_cancel
-               .long   sys_exit_group
-               .long   sys_lookup_dcookie
-/* 250 */      .long   sys_epoll_create
-               .long   ABI(sys_epoll_ctl, sys_oabi_epoll_ctl)
-               .long   ABI(sys_epoll_wait, sys_oabi_epoll_wait)
-               .long   sys_remap_file_pages
-               .long   sys_ni_syscall  /* sys_set_thread_area */
-/* 255 */      .long   sys_ni_syscall  /* sys_get_thread_area */
-               .long   sys_set_tid_address
-               .long   sys_timer_create
-               .long   sys_timer_settime
-               .long   sys_timer_gettime
-/* 260 */      .long   sys_timer_getoverrun
-               .long   sys_timer_delete
-               .long   sys_clock_settime
-               .long   sys_clock_gettime
-               .long   sys_clock_getres
-/* 265 */      .long   sys_clock_nanosleep
-               .long   sys_statfs64_wrapper
-               .long   sys_fstatfs64_wrapper
-               .long   sys_tgkill
-               .long   sys_utimes
-/* 270 */      .long   sys_arm_fadvise64_64
-               .long   sys_pciconfig_iobase
-               .long   sys_pciconfig_read
-               .long   sys_pciconfig_write
-               .long   sys_mq_open
-/* 275 */      .long   sys_mq_unlink
-               .long   sys_mq_timedsend
-               .long   sys_mq_timedreceive
-               .long   sys_mq_notify
-               .long   sys_mq_getsetattr
-/* 280 */      .long   sys_waitid
-               .long   sys_socket
-               .long   sys_bind
-               .long   sys_connect
-               .long   sys_listen
-/* 285 */      .long   sys_accept
-               .long   sys_getsockname
-               .long   sys_getpeername
-               .long   sys_socketpair
-               .long   sys_send
-/* 290 */      .long   sys_sendto
-               .long   sys_recv
-               .long   sys_recvfrom
-               .long   sys_shutdown
-               .long   sys_setsockopt
-/* 295 */      .long   sys_getsockopt
-               .long   sys_sendmsg
-               .long   sys_recvmsg
-               .long   ABI(sys_semop, sys_oabi_semop)
-               .long   sys_semget
-/* 300 */      .long   sys_semctl
-               .long   sys_msgsnd
-               .long   sys_msgrcv
-               .long   sys_msgget
-               .long   sys_msgctl
-/* 305 */      .long   sys_shmat
-               .long   sys_shmdt
-               .long   sys_shmget
-               .long   sys_shmctl
-               .long   sys_add_key
-/* 310 */      .long   sys_request_key
-               .long   sys_keyctl
-               .long   ABI(sys_semtimedop, sys_oabi_semtimedop)
-/* vserver */  .long   sys_ni_syscall
-               .long   sys_ioprio_set
-/* 315 */      .long   sys_ioprio_get
-               .long   sys_inotify_init
-               .long   sys_inotify_add_watch
-               .long   sys_inotify_rm_watch
-               .long   sys_mbind
-/* 320 */      .long   sys_get_mempolicy
-               .long   sys_set_mempolicy
-
-               .rept   NR_syscalls - (. - 100b) / 4
-                       .long   sys_ni_syscall
-               .endr
+/* 0 */                CALL(sys_restart_syscall)
+               CALL(sys_exit)
+               CALL(sys_fork_wrapper)
+               CALL(sys_read)
+               CALL(sys_write)
+/* 5 */                CALL(sys_open)
+               CALL(sys_close)
+               CALL(sys_ni_syscall)            /* was sys_waitpid */
+               CALL(sys_creat)
+               CALL(sys_link)
+/* 10 */       CALL(sys_unlink)
+               CALL(sys_execve_wrapper)
+               CALL(sys_chdir)
+               CALL(OBSOLETE(sys_time))        /* used by libc4 */
+               CALL(sys_mknod)
+/* 15 */       CALL(sys_chmod)
+               CALL(sys_lchown16)
+               CALL(sys_ni_syscall)            /* was sys_break */
+               CALL(sys_ni_syscall)            /* was sys_stat */
+               CALL(sys_lseek)
+/* 20 */       CALL(sys_getpid)
+               CALL(sys_mount)
+               CALL(OBSOLETE(sys_oldumount))   /* used by libc4 */
+               CALL(sys_setuid16)
+               CALL(sys_getuid16)
+/* 25 */       CALL(OBSOLETE(sys_stime))
+               CALL(sys_ptrace)
+               CALL(OBSOLETE(sys_alarm))       /* used by libc4 */
+               CALL(sys_ni_syscall)            /* was sys_fstat */
+               CALL(sys_pause)
+/* 30 */       CALL(OBSOLETE(sys_utime))       /* used by libc4 */
+               CALL(sys_ni_syscall)            /* was sys_stty */
+               CALL(sys_ni_syscall)            /* was sys_getty */
+               CALL(sys_access)
+               CALL(sys_nice)
+/* 35 */       CALL(sys_ni_syscall)            /* was sys_ftime */
+               CALL(sys_sync)
+               CALL(sys_kill)
+               CALL(sys_rename)
+               CALL(sys_mkdir)
+/* 40 */       CALL(sys_rmdir)
+               CALL(sys_dup)
+               CALL(sys_pipe)
+               CALL(sys_times)
+               CALL(sys_ni_syscall)            /* was sys_prof */
+/* 45 */       CALL(sys_brk)
+               CALL(sys_setgid16)
+               CALL(sys_getgid16)
+               CALL(sys_ni_syscall)            /* was sys_signal */
+               CALL(sys_geteuid16)
+/* 50 */       CALL(sys_getegid16)
+               CALL(sys_acct)
+               CALL(sys_umount)
+               CALL(sys_ni_syscall)            /* was sys_lock */
+               CALL(sys_ioctl)
+/* 55 */       CALL(sys_fcntl)
+               CALL(sys_ni_syscall)            /* was sys_mpx */
+               CALL(sys_setpgid)
+               CALL(sys_ni_syscall)            /* was sys_ulimit */
+               CALL(sys_ni_syscall)            /* was sys_olduname */
+/* 60 */       CALL(sys_umask)
+               CALL(sys_chroot)
+               CALL(sys_ustat)
+               CALL(sys_dup2)
+               CALL(sys_getppid)
+/* 65 */       CALL(sys_getpgrp)
+               CALL(sys_setsid)
+               CALL(sys_sigaction)
+               CALL(sys_ni_syscall)            /* was sys_sgetmask */
+               CALL(sys_ni_syscall)            /* was sys_ssetmask */
+/* 70 */       CALL(sys_setreuid16)
+               CALL(sys_setregid16)
+               CALL(sys_sigsuspend_wrapper)
+               CALL(sys_sigpending)
+               CALL(sys_sethostname)
+/* 75 */       CALL(sys_setrlimit)
+               CALL(OBSOLETE(sys_old_getrlimit)) /* used by libc4 */
+               CALL(sys_getrusage)
+               CALL(sys_gettimeofday)
+               CALL(sys_settimeofday)
+/* 80 */       CALL(sys_getgroups16)
+               CALL(sys_setgroups16)
+               CALL(OBSOLETE(old_select))      /* used by libc4 */
+               CALL(sys_symlink)
+               CALL(sys_ni_syscall)            /* was sys_lstat */
+/* 85 */       CALL(sys_readlink)
+               CALL(sys_uselib)
+               CALL(sys_swapon)
+               CALL(sys_reboot)
+               CALL(OBSOLETE(old_readdir))     /* used by libc4 */
+/* 90 */       CALL(OBSOLETE(old_mmap))        /* used by libc4 */
+               CALL(sys_munmap)
+               CALL(sys_truncate)
+               CALL(sys_ftruncate)
+               CALL(sys_fchmod)
+/* 95 */       CALL(sys_fchown16)
+               CALL(sys_getpriority)
+               CALL(sys_setpriority)
+               CALL(sys_ni_syscall)            /* was sys_profil */
+               CALL(sys_statfs)
+/* 100 */      CALL(sys_fstatfs)
+               CALL(sys_ni_syscall)
+               CALL(OBSOLETE(sys_socketcall))
+               CALL(sys_syslog)
+               CALL(sys_setitimer)
+/* 105 */      CALL(sys_getitimer)
+               CALL(sys_newstat)
+               CALL(sys_newlstat)
+               CALL(sys_newfstat)
+               CALL(sys_ni_syscall)            /* was sys_uname */
+/* 110 */      CALL(sys_ni_syscall)            /* was sys_iopl */
+               CALL(sys_vhangup)
+               CALL(sys_ni_syscall)
+               CALL(OBSOLETE(sys_syscall))     /* call a syscall */
+               CALL(sys_wait4)
+/* 115 */      CALL(sys_swapoff)
+               CALL(sys_sysinfo)
+               CALL(OBSOLETE(ABI(sys_ipc, sys_oabi_ipc)))
+               CALL(sys_fsync)
+               CALL(sys_sigreturn_wrapper)
+/* 120 */      CALL(sys_clone_wrapper)
+               CALL(sys_setdomainname)
+               CALL(sys_newuname)
+               CALL(sys_ni_syscall)
+               CALL(sys_adjtimex)
+/* 125 */      CALL(sys_mprotect)
+               CALL(sys_sigprocmask)
+               CALL(sys_ni_syscall)            /* was sys_create_module */
+               CALL(sys_init_module)
+               CALL(sys_delete_module)
+/* 130 */      CALL(sys_ni_syscall)            /* was sys_get_kernel_syms */
+               CALL(sys_quotactl)
+               CALL(sys_getpgid)
+               CALL(sys_fchdir)
+               CALL(sys_bdflush)
+/* 135 */      CALL(sys_sysfs)
+               CALL(sys_personality)
+               CALL(sys_ni_syscall)            /* CALL(_sys_afs_syscall) */
+               CALL(sys_setfsuid16)
+               CALL(sys_setfsgid16)
+/* 140 */      CALL(sys_llseek)
+               CALL(sys_getdents)
+               CALL(sys_select)
+               CALL(sys_flock)
+               CALL(sys_msync)
+/* 145 */      CALL(sys_readv)
+               CALL(sys_writev)
+               CALL(sys_getsid)
+               CALL(sys_fdatasync)
+               CALL(sys_sysctl)
+/* 150 */      CALL(sys_mlock)
+               CALL(sys_munlock)
+               CALL(sys_mlockall)
+               CALL(sys_munlockall)
+               CALL(sys_sched_setparam)
+/* 155 */      CALL(sys_sched_getparam)
+               CALL(sys_sched_setscheduler)
+               CALL(sys_sched_getscheduler)
+               CALL(sys_sched_yield)
+               CALL(sys_sched_get_priority_max)
+/* 160 */      CALL(sys_sched_get_priority_min)
+               CALL(sys_sched_rr_get_interval)
+               CALL(sys_nanosleep)
+               CALL(sys_arm_mremap)
+               CALL(sys_setresuid16)
+/* 165 */      CALL(sys_getresuid16)
+               CALL(sys_ni_syscall)
+               CALL(sys_ni_syscall)            /* was sys_query_module */
+               CALL(sys_poll)
+               CALL(sys_nfsservctl)
+/* 170 */      CALL(sys_setresgid16)
+               CALL(sys_getresgid16)
+               CALL(sys_prctl)
+               CALL(sys_rt_sigreturn_wrapper)
+               CALL(sys_rt_sigaction)
+/* 175 */      CALL(sys_rt_sigprocmask)
+               CALL(sys_rt_sigpending)
+               CALL(sys_rt_sigtimedwait)
+               CALL(sys_rt_sigqueueinfo)
+               CALL(sys_rt_sigsuspend_wrapper)
+/* 180 */      CALL(ABI(sys_pread64, sys_oabi_pread64))
+               CALL(ABI(sys_pwrite64, sys_oabi_pwrite64))
+               CALL(sys_chown16)
+               CALL(sys_getcwd)
+               CALL(sys_capget)
+/* 185 */      CALL(sys_capset)
+               CALL(sys_sigaltstack_wrapper)
+               CALL(sys_sendfile)
+               CALL(sys_ni_syscall)
+               CALL(sys_ni_syscall)
+/* 190 */      CALL(sys_vfork_wrapper)
+               CALL(sys_getrlimit)
+               CALL(sys_mmap2)
+               CALL(ABI(sys_truncate64, sys_oabi_truncate64))
+               CALL(ABI(sys_ftruncate64, sys_oabi_ftruncate64))
+/* 195 */      CALL(ABI(sys_stat64, sys_oabi_stat64))
+               CALL(ABI(sys_lstat64, sys_oabi_lstat64))
+               CALL(ABI(sys_fstat64, sys_oabi_fstat64))
+               CALL(sys_lchown)
+               CALL(sys_getuid)
+/* 200 */      CALL(sys_getgid)
+               CALL(sys_geteuid)
+               CALL(sys_getegid)
+               CALL(sys_setreuid)
+               CALL(sys_setregid)
+/* 205 */      CALL(sys_getgroups)
+               CALL(sys_setgroups)
+               CALL(sys_fchown)
+               CALL(sys_setresuid)
+               CALL(sys_getresuid)
+/* 210 */      CALL(sys_setresgid)
+               CALL(sys_getresgid)
+               CALL(sys_chown)
+               CALL(sys_setuid)
+               CALL(sys_setgid)
+/* 215 */      CALL(sys_setfsuid)
+               CALL(sys_setfsgid)
+               CALL(sys_getdents64)
+               CALL(sys_pivot_root)
+               CALL(sys_mincore)
+/* 220 */      CALL(sys_madvise)
+               CALL(ABI(sys_fcntl64, sys_oabi_fcntl64))
+               CALL(sys_ni_syscall) /* TUX */
+               CALL(sys_ni_syscall)
+               CALL(sys_gettid)
+/* 225 */      CALL(ABI(sys_readahead, sys_oabi_readahead))
+               CALL(sys_setxattr)
+               CALL(sys_lsetxattr)
+               CALL(sys_fsetxattr)
+               CALL(sys_getxattr)
+/* 230 */      CALL(sys_lgetxattr)
+               CALL(sys_fgetxattr)
+               CALL(sys_listxattr)
+               CALL(sys_llistxattr)
+               CALL(sys_flistxattr)
+/* 235 */      CALL(sys_removexattr)
+               CALL(sys_lremovexattr)
+               CALL(sys_fremovexattr)
+               CALL(sys_tkill)
+               CALL(sys_sendfile64)
+/* 240 */      CALL(sys_futex)
+               CALL(sys_sched_setaffinity)
+               CALL(sys_sched_getaffinity)
+               CALL(sys_io_setup)
+               CALL(sys_io_destroy)
+/* 245 */      CALL(sys_io_getevents)
+               CALL(sys_io_submit)
+               CALL(sys_io_cancel)
+               CALL(sys_exit_group)
+               CALL(sys_lookup_dcookie)
+/* 250 */      CALL(sys_epoll_create)
+               CALL(ABI(sys_epoll_ctl, sys_oabi_epoll_ctl))
+               CALL(ABI(sys_epoll_wait, sys_oabi_epoll_wait))
+               CALL(sys_remap_file_pages)
+               CALL(sys_ni_syscall)    /* sys_set_thread_area */
+/* 255 */      CALL(sys_ni_syscall)    /* sys_get_thread_area */
+               CALL(sys_set_tid_address)
+               CALL(sys_timer_create)
+               CALL(sys_timer_settime)
+               CALL(sys_timer_gettime)
+/* 260 */      CALL(sys_timer_getoverrun)
+               CALL(sys_timer_delete)
+               CALL(sys_clock_settime)
+               CALL(sys_clock_gettime)
+               CALL(sys_clock_getres)
+/* 265 */      CALL(sys_clock_nanosleep)
+               CALL(sys_statfs64_wrapper)
+               CALL(sys_fstatfs64_wrapper)
+               CALL(sys_tgkill)
+               CALL(sys_utimes)
+/* 270 */      CALL(sys_arm_fadvise64_64)
+               CALL(sys_pciconfig_iobase)
+               CALL(sys_pciconfig_read)
+               CALL(sys_pciconfig_write)
+               CALL(sys_mq_open)
+/* 275 */      CALL(sys_mq_unlink)
+               CALL(sys_mq_timedsend)
+               CALL(sys_mq_timedreceive)
+               CALL(sys_mq_notify)
+               CALL(sys_mq_getsetattr)
+/* 280 */      CALL(sys_waitid)
+               CALL(sys_socket)
+               CALL(sys_bind)
+               CALL(sys_connect)
+               CALL(sys_listen)
+/* 285 */      CALL(sys_accept)
+               CALL(sys_getsockname)
+               CALL(sys_getpeername)
+               CALL(sys_socketpair)
+               CALL(sys_send)
+/* 290 */      CALL(sys_sendto)
+               CALL(sys_recv)
+               CALL(sys_recvfrom)
+               CALL(sys_shutdown)
+               CALL(sys_setsockopt)
+/* 295 */      CALL(sys_getsockopt)
+               CALL(sys_sendmsg)
+               CALL(sys_recvmsg)
+               CALL(ABI(sys_semop, sys_oabi_semop))
+               CALL(sys_semget)
+/* 300 */      CALL(sys_semctl)
+               CALL(sys_msgsnd)
+               CALL(sys_msgrcv)
+               CALL(sys_msgget)
+               CALL(sys_msgctl)
+/* 305 */      CALL(sys_shmat)
+               CALL(sys_shmdt)
+               CALL(sys_shmget)
+               CALL(sys_shmctl)
+               CALL(sys_add_key)
+/* 310 */      CALL(sys_request_key)
+               CALL(sys_keyctl)
+               CALL(ABI(sys_semtimedop, sys_oabi_semtimedop))
+/* vserver */  CALL(sys_ni_syscall)
+               CALL(sys_ioprio_set)
+/* 315 */      CALL(sys_ioprio_get)
+               CALL(sys_inotify_init)
+               CALL(sys_inotify_add_watch)
+               CALL(sys_inotify_rm_watch)
+               CALL(sys_mbind)
+/* 320 */      CALL(sys_get_mempolicy)
+               CALL(sys_set_mempolicy)
+#ifndef syscalls_counted
+.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
+#define syscalls_counted
 #endif
+.rept syscalls_padding
+               CALL(sys_ni_syscall)
+.endr
index 2b92ce85f97feef93415fd25c9260afa6367a6ae..dbcb11a31f78167b5577c55cfe4660c922043a20 100644 (file)
@@ -87,7 +87,11 @@ ENTRY(ret_from_fork)
        b       ret_slow_syscall
        
 
+       .equ NR_syscalls,0
+#define CALL(x) .equ NR_syscalls,NR_syscalls+1
 #include "calls.S"
+#undef CALL
+#define CALL(x) .long x
 
 /*=============================================================================
  * SWI handler
index 31820170f3068600a373915227d9f6a090cdf9f1..a0724f2b24cec783a242887971b5fc0d2e5a6592 100644 (file)
@@ -469,7 +469,9 @@ static void cp_clcd_enable(struct clcd_fb *fb)
        if (fb->fb.var.bits_per_pixel <= 8)
                val = CM_CTRL_LCDMUXSEL_VGA_8421BPP;
        else if (fb->fb.var.bits_per_pixel <= 16)
-               val = CM_CTRL_LCDMUXSEL_VGA_16BPP;
+               val = CM_CTRL_LCDMUXSEL_VGA_16BPP
+                       | CM_CTRL_LCDEN0 | CM_CTRL_LCDEN1
+                       | CM_CTRL_STATIC1 | CM_CTRL_STATIC2;
        else
                val = 0; /* no idea for this, don't trust the docs */
 
index 9cbe5eef492b26a26a4d586ad6d96266f37de8fb..fc1067783f6d18ee7fb8a0572be4c9d81b871a17 100644 (file)
  *     14-Jan-2005 BJD  Added s3c24xx_init_clocks() call
  *     10-Mar-2005 LCVR Changed S3C2410_{VA,SZ} to S3C24XX_{VA,SZ} & IODESC_ENT
  *     14-Mar-2005 BJD  Updated for __iomem
+ *     15-Jan-2006 LCVR Updated S3C2410_PA_##x to new S3C24XX_PA_##x macro
 */
 
 /* todo - fix when rmk changes iodescs to use `void __iomem *` */
 
-#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C2410_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
+#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
 
 #ifndef MHZ
 #define MHZ (1000*1000)
index f58406e6ef5a69a3d65103597813ecffdd3a587d..b8d994a24d1c18173252feedadceb562449a2a23 100644 (file)
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  *
  * Modifications:
+ *     15-Jan-2006 LCVR Using S3C24XX_PA_##x macro for common S3C24XX devices
  *     10-Mar-2005 LCVR Changed S3C2410_{VA,SZ} to S3C24XX_{VA,SZ}
  *     10-Feb-2005 BJD  Added camera from guillaume.gourat@nexvision.tv
  *     29-Aug-2004 BJD  Added timers 0 through 3
@@ -46,8 +47,8 @@ struct platform_device *s3c24xx_uart_devs[3];
 
 static struct resource s3c_usb_resource[] = {
        [0] = {
-               .start = S3C2410_PA_USBHOST,
-               .end   = S3C2410_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
+               .start = S3C24XX_PA_USBHOST,
+               .end   = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -76,8 +77,8 @@ EXPORT_SYMBOL(s3c_device_usb);
 
 static struct resource s3c_lcd_resource[] = {
        [0] = {
-               .start = S3C2410_PA_LCD,
-               .end   = S3C2410_PA_LCD + S3C24XX_SZ_LCD - 1,
+               .start = S3C24XX_PA_LCD,
+               .end   = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -139,8 +140,8 @@ EXPORT_SYMBOL(s3c_device_nand);
 
 static struct resource s3c_usbgadget_resource[] = {
        [0] = {
-               .start = S3C2410_PA_USBDEV,
-               .end   = S3C2410_PA_USBDEV + S3C24XX_SZ_USBDEV - 1,
+               .start = S3C24XX_PA_USBDEV,
+               .end   = S3C24XX_PA_USBDEV + S3C24XX_SZ_USBDEV - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -164,8 +165,8 @@ EXPORT_SYMBOL(s3c_device_usbgadget);
 
 static struct resource s3c_wdt_resource[] = {
        [0] = {
-               .start = S3C2410_PA_WATCHDOG,
-               .end   = S3C2410_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,
+               .start = S3C24XX_PA_WATCHDOG,
+               .end   = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -189,8 +190,8 @@ EXPORT_SYMBOL(s3c_device_wdt);
 
 static struct resource s3c_i2c_resource[] = {
        [0] = {
-               .start = S3C2410_PA_IIC,
-               .end   = S3C2410_PA_IIC + S3C24XX_SZ_IIC - 1,
+               .start = S3C24XX_PA_IIC,
+               .end   = S3C24XX_PA_IIC + S3C24XX_SZ_IIC - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -214,8 +215,8 @@ EXPORT_SYMBOL(s3c_device_i2c);
 
 static struct resource s3c_iis_resource[] = {
        [0] = {
-               .start = S3C2410_PA_IIS,
-               .end   = S3C2410_PA_IIS + S3C24XX_SZ_IIS -1,
+               .start = S3C24XX_PA_IIS,
+               .end   = S3C24XX_PA_IIS + S3C24XX_SZ_IIS -1,
                .flags = IORESOURCE_MEM,
        }
 };
@@ -239,8 +240,8 @@ EXPORT_SYMBOL(s3c_device_iis);
 
 static struct resource s3c_rtc_resource[] = {
        [0] = {
-               .start = S3C2410_PA_RTC,
-               .end   = S3C2410_PA_RTC + 0xff,
+               .start = S3C24XX_PA_RTC,
+               .end   = S3C24XX_PA_RTC + 0xff,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -268,8 +269,8 @@ EXPORT_SYMBOL(s3c_device_rtc);
 
 static struct resource s3c_adc_resource[] = {
        [0] = {
-               .start = S3C2410_PA_ADC,
-               .end   = S3C2410_PA_ADC + S3C24XX_SZ_ADC - 1,
+               .start = S3C24XX_PA_ADC,
+               .end   = S3C24XX_PA_ADC + S3C24XX_SZ_ADC - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -316,8 +317,8 @@ EXPORT_SYMBOL(s3c_device_sdi);
 
 static struct resource s3c_spi0_resource[] = {
        [0] = {
-               .start = S3C2410_PA_SPI,
-               .end   = S3C2410_PA_SPI + 0x1f,
+               .start = S3C24XX_PA_SPI,
+               .end   = S3C24XX_PA_SPI + 0x1f,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -341,8 +342,8 @@ EXPORT_SYMBOL(s3c_device_spi0);
 
 static struct resource s3c_spi1_resource[] = {
        [0] = {
-               .start = S3C2410_PA_SPI + 0x20,
-               .end   = S3C2410_PA_SPI + 0x20 + 0x1f,
+               .start = S3C24XX_PA_SPI + 0x20,
+               .end   = S3C24XX_PA_SPI + 0x20 + 0x1f,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -366,8 +367,8 @@ EXPORT_SYMBOL(s3c_device_spi1);
 
 static struct resource s3c_timer0_resource[] = {
        [0] = {
-               .start = S3C2410_PA_TIMER + 0x0C,
-               .end   = S3C2410_PA_TIMER + 0x0C + 0xB,
+               .start = S3C24XX_PA_TIMER + 0x0C,
+               .end   = S3C24XX_PA_TIMER + 0x0C + 0xB,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -391,8 +392,8 @@ EXPORT_SYMBOL(s3c_device_timer0);
 
 static struct resource s3c_timer1_resource[] = {
        [0] = {
-               .start = S3C2410_PA_TIMER + 0x18,
-               .end   = S3C2410_PA_TIMER + 0x23,
+               .start = S3C24XX_PA_TIMER + 0x18,
+               .end   = S3C24XX_PA_TIMER + 0x23,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -416,8 +417,8 @@ EXPORT_SYMBOL(s3c_device_timer1);
 
 static struct resource s3c_timer2_resource[] = {
        [0] = {
-               .start = S3C2410_PA_TIMER + 0x24,
-               .end   = S3C2410_PA_TIMER + 0x2F,
+               .start = S3C24XX_PA_TIMER + 0x24,
+               .end   = S3C24XX_PA_TIMER + 0x2F,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -441,8 +442,8 @@ EXPORT_SYMBOL(s3c_device_timer2);
 
 static struct resource s3c_timer3_resource[] = {
        [0] = {
-               .start = S3C2410_PA_TIMER + 0x30,
-               .end   = S3C2410_PA_TIMER + 0x3B,
+               .start = S3C24XX_PA_TIMER + 0x30,
+               .end   = S3C24XX_PA_TIMER + 0x3B,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
index 65feaf20d23e842d1d46ba88ed674f4942558c7a..4dbd8e758ea6f9691f73e5c06439fa4d2efec2fc 100644 (file)
@@ -1152,7 +1152,7 @@ static int __init s3c2410_init_dma(void)
 
        printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n");
 
-       dma_base = ioremap(S3C2410_PA_DMA, 0x200);
+       dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
        if (dma_base == NULL) {
                printk(KERN_ERR "dma failed to remap register block\n");
                return -ENOMEM;
index 61768dac7feed7b3ebaada47062d0f71831d2748..e9a055b779b7f1158c1759ebd7cecab08e4a2ab7 100644 (file)
@@ -133,12 +133,12 @@ ENTRY(s3c2410_cpu_resume)
        @@ load UART to allow us to print the two characters for
        @@ resume debug
 
-       mov     r2, #S3C2410_PA_UART & 0xff000000
-       orr     r2, r2, #S3C2410_PA_UART & 0xff000
+       mov     r2, #S3C24XX_PA_UART & 0xff000000
+       orr     r2, r2, #S3C24XX_PA_UART & 0xff000
 
 #if 0
        /* SMDK2440 LED set */
-       mov     r14, #S3C2410_PA_GPIO
+       mov     r14, #S3C24XX_PA_GPIO
        ldr     r12, [ r14, #0x54 ]
        bic     r12, r12, #3<<4
        orr     r12, r12, #1<<7
index de3ce1eec2ece4d222a2293bfa325fb585104433..da9b35974118d34d2b6fac17bb246306a6e19228 100644 (file)
@@ -142,7 +142,7 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
                return NULL;
        addr = (unsigned long)area->addr;
        if (remap_area_pages(addr, pfn, size, flags)) {
-               vfree(addr);
+               vfree((void *)addr);
                return NULL;
        }
        return (void __iomem *) (offset + (char *)addr);
index d0245a31d4dd15f8382e0de7087b3027e97acbc7..ef8d30a185a97574657ee66d31134b9feec76363 100644 (file)
@@ -343,6 +343,12 @@ static struct mem_types mem_types[] __initdata = {
                                PMD_SECT_AP_WRITE | PMD_SECT_BUFFERABLE |
                                PMD_SECT_TEX(1),
                .domain    = DOMAIN_IO,
+       },
+       [MT_NONSHARED_DEVICE] = {
+               .prot_l1   = PMD_TYPE_TABLE,
+               .prot_sect = PMD_TYPE_SECT | PMD_SECT_NONSHARED_DEV |
+                               PMD_SECT_AP_WRITE,
+               .domain    = DOMAIN_IO,
        }
 };
 
index 394814e576720998c19573afcf23707695836e72..0dd92a23d62206e9d0fe0e59976c39872dee8ada 100644 (file)
@@ -405,10 +405,6 @@ static void __init init_centaur(struct cpuinfo_x86 *c)
                                winchip2_protect_mcr();
 #endif
                                break;
-                       case 10:
-                               name="4";
-                               /* no info on the WC4 yet */
-                               break;
                        default:
                                name="??";
                        }
index 0f1eb507233b701c6bb7b158104e0e5cfd9e4d85..26892d2099b0278766b993cbde60d17ef2fcb534 100644 (file)
@@ -96,6 +96,7 @@ config X86_POWERNOW_K8_ACPI
 
 config X86_GX_SUSPMOD
        tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
+       depends on PCI
        help
         This add the CPUFreq driver for NatSemi Geode processors which
         support suspend modulation.
index 270f2188d68b1857d3ef59c3a71adf7f106de2c4..cc73a7ae34bc3f92f7177bd606b698bcc192e28b 100644 (file)
@@ -52,6 +52,7 @@ enum {
 
 
 static int has_N44_O17_errata[NR_CPUS];
+static int has_N60_errata[NR_CPUS];
 static unsigned int stock_freq;
 static struct cpufreq_driver p4clockmod_driver;
 static unsigned int cpufreq_p4_get(unsigned int cpu);
@@ -226,6 +227,12 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
        case 0x0f12:
                has_N44_O17_errata[policy->cpu] = 1;
                dprintk("has errata -- disabling low frequencies\n");
+               break;
+
+       case 0x0f29:
+               has_N60_errata[policy->cpu] = 1;
+               dprintk("has errata -- disabling frequencies lower than 2ghz\n");
+               break;
        }
        
        /* get max frequency */
@@ -237,6 +244,8 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
        for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) {
                if ((i<2) && (has_N44_O17_errata[policy->cpu]))
                        p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+               else if (has_N60_errata[policy->cpu] && p4clockmod_table[i].frequency < 2000000)
+                       p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID;
                else
                        p4clockmod_table[i].frequency = (stock_freq * i)/8;
        }
index fbfd374aa336aff467612054031a19356b41b1a7..af591c73345fa4120e6716b37e262b35e12754af 100644 (file)
@@ -43,13 +43,23 @@ static struct _cache_table cache_table[] __cpuinitdata =
        { 0x2c, LVL_1_DATA, 32 },       /* 8-way set assoc, 64 byte line size */
        { 0x30, LVL_1_INST, 32 },       /* 8-way set assoc, 64 byte line size */
        { 0x39, LVL_2,      128 },      /* 4-way set assoc, sectored cache, 64 byte line size */
+       { 0x3a, LVL_2,      192 },      /* 6-way set assoc, sectored cache, 64 byte line size */
        { 0x3b, LVL_2,      128 },      /* 2-way set assoc, sectored cache, 64 byte line size */
        { 0x3c, LVL_2,      256 },      /* 4-way set assoc, sectored cache, 64 byte line size */
+       { 0x3d, LVL_2,      384 },      /* 6-way set assoc, sectored cache, 64 byte line size */
+       { 0x3e, LVL_2,      512 },      /* 4-way set assoc, sectored cache, 64 byte line size */
        { 0x41, LVL_2,      128 },      /* 4-way set assoc, 32 byte line size */
        { 0x42, LVL_2,      256 },      /* 4-way set assoc, 32 byte line size */
        { 0x43, LVL_2,      512 },      /* 4-way set assoc, 32 byte line size */
        { 0x44, LVL_2,      1024 },     /* 4-way set assoc, 32 byte line size */
        { 0x45, LVL_2,      2048 },     /* 4-way set assoc, 32 byte line size */
+       { 0x46, LVL_3,      4096 },     /* 4-way set assoc, 64 byte line size */
+       { 0x47, LVL_3,      8192 },     /* 8-way set assoc, 64 byte line size */
+       { 0x49, LVL_3,      4096 },     /* 16-way set assoc, 64 byte line size */
+       { 0x4a, LVL_3,      6144 },     /* 12-way set assoc, 64 byte line size */
+       { 0x4b, LVL_3,      8192 },     /* 16-way set assoc, 64 byte line size */
+       { 0x4c, LVL_3,     12288 },     /* 12-way set assoc, 64 byte line size */
+       { 0x4d, LVL_3,     16384 },     /* 16-way set assoc, 64 byte line size */
        { 0x60, LVL_1_DATA, 16 },       /* 8-way set assoc, sectored cache, 64 byte line size */
        { 0x66, LVL_1_DATA, 8 },        /* 4-way set assoc, sectored cache, 64 byte line size */
        { 0x67, LVL_1_DATA, 16 },       /* 4-way set assoc, sectored cache, 64 byte line size */
@@ -57,6 +67,7 @@ static struct _cache_table cache_table[] __cpuinitdata =
        { 0x70, LVL_TRACE,  12 },       /* 8-way set assoc */
        { 0x71, LVL_TRACE,  16 },       /* 8-way set assoc */
        { 0x72, LVL_TRACE,  32 },       /* 8-way set assoc */
+       { 0x73, LVL_TRACE,  64 },       /* 8-way set assoc */
        { 0x78, LVL_2,    1024 },       /* 4-way set assoc, 64 byte line size */
        { 0x79, LVL_2,     128 },       /* 8-way set assoc, sectored cache, 64 byte line size */
        { 0x7a, LVL_2,     256 },       /* 8-way set assoc, sectored cache, 64 byte line size */
index 1e9db198c440e3a1dac2c5bdcbe38038a31f3c26..3b4618bed70d56fd1bc79087652b7b3c10791376 100644 (file)
 #include <asm/msr.h>
 #include "mtrr.h"
 
-#define MTRR_VERSION            "2.0 (20020519)"
-
 u32 num_var_ranges = 0;
 
 unsigned int *usage_table;
-static DECLARE_MUTEX(main_lock);
+static DECLARE_MUTEX(mtrr_sem);
 
 u32 size_or_mask, size_and_mask;
 
@@ -335,7 +333,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
        /* No CPU hotplug when we change MTRR entries */
        lock_cpu_hotplug();
        /*  Search for existing MTRR  */
-       down(&main_lock);
+       down(&mtrr_sem);
        for (i = 0; i < num_var_ranges; ++i) {
                mtrr_if->get(i, &lbase, &lsize, &ltype);
                if (base >= lbase + lsize)
@@ -373,7 +371,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
                printk(KERN_INFO "mtrr: no more MTRRs available\n");
        error = i;
  out:
-       up(&main_lock);
+       up(&mtrr_sem);
        unlock_cpu_hotplug();
        return error;
 }
@@ -466,7 +464,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
        max = num_var_ranges;
        /* No CPU hotplug when we change MTRR entries */
        lock_cpu_hotplug();
-       down(&main_lock);
+       down(&mtrr_sem);
        if (reg < 0) {
                /*  Search for existing MTRR  */
                for (i = 0; i < max; ++i) {
@@ -505,7 +503,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
                set_mtrr(reg, 0, 0, 0);
        error = reg;
  out:
-       up(&main_lock);
+       up(&mtrr_sem);
        unlock_cpu_hotplug();
        return error;
 }
@@ -671,7 +669,6 @@ void __init mtrr_bp_init(void)
                        break;
                }
        }
-       printk(KERN_INFO "mtrr: v%s\n",MTRR_VERSION);
 
        if (mtrr_if) {
                set_num_var_ranges();
@@ -688,7 +685,7 @@ void mtrr_ap_init(void)
        if (!mtrr_if || !use_intel())
                return;
        /*
-        * Ideally we should hold main_lock here to avoid mtrr entries changed,
+        * Ideally we should hold mtrr_sem here to avoid mtrr entries changed,
         * but this routine will be called in cpu boot time, holding the lock
         * breaks it. This routine is called in two cases: 1.very earily time
         * of software resume, when there absolutely isn't mtrr entry changes;
index e715aa930036aa1590aae77b09ad27f7c87c7cbb..3ca59cad05f33d41ac3e663070d4e44223449a37 100644 (file)
@@ -539,6 +539,11 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
                case PCI_DEVICE_ID_INTEL_ICH7_30:
                case PCI_DEVICE_ID_INTEL_ICH7_31:
                case PCI_DEVICE_ID_INTEL_ESB2_0:
+               case PCI_DEVICE_ID_INTEL_ICH8_0:
+               case PCI_DEVICE_ID_INTEL_ICH8_1:
+               case PCI_DEVICE_ID_INTEL_ICH8_2:
+               case PCI_DEVICE_ID_INTEL_ICH8_3:
+               case PCI_DEVICE_ID_INTEL_ICH8_4:
                        r->name = "PIIX/ICH";
                        r->get = pirq_piix_get;
                        r->set = pirq_piix_set;
index 4bb4d4b0f73ad00ce6e66e50a29ad877a2102c24..0ee8a983708c078b0e3e8f9b7c27548cd1936845 100644 (file)
@@ -36,8 +36,7 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
        while (1) {
                ++cfg_num;
                if (cfg_num >= pci_mmcfg_config_num) {
-                       /* Not found - fallback to type 1 */
-                       return 0;
+                       break;
                }
                cfg = &pci_mmcfg_config[cfg_num];
                if (cfg->pci_segment_group_number != seg)
@@ -46,6 +45,18 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
                    (cfg->end_bus_number >= bus))
                        return cfg->base_address;
        }
+
+       /* Handle more broken MCFG tables on Asus etc.
+          They only contain a single entry for bus 0-0. Assume
+          this applies to all busses. */
+       cfg = &pci_mmcfg_config[0];
+       if (pci_mmcfg_config_num == 1 &&
+               cfg->pci_segment_group_number == 0 &&
+               (cfg->start_bus_number | cfg->end_bus_number) == 0)
+               return cfg->base_address;
+
+       /* Fall back to type 0 */
+       return 0;
 }
 
 static inline void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
index 403a80a58c13bf9ef89118ae4f4b7063d28df7e0..60a464bfd9e27ce2afe46bb0de051806b9b0cbfa 100644 (file)
@@ -512,7 +512,7 @@ ia64_state_save:
        st8 [temp1]=r12         // os_status, default is cold boot
        mov r6=IA64_MCA_SAME_CONTEXT
        ;;
-       st8 [temp1]=r6          // context, default is same context
+       st8 [temp2]=r6          // context, default is same context
 
        // Save the pt_regs data that is not in minstate.  The previous code
        // left regs at sos.
index 43b45b65ee5a9da2c446d712b67ba152f1e4fce0..f9e0ae936d1a9e278ea56bb9af1d35ae8159df26 100644 (file)
@@ -1283,8 +1283,9 @@ within_logging_rate_limit (void)
 
        if (jiffies - last_time > 5*HZ)
                count = 0;
-       if (++count < 5) {
+       if (count < 5) {
                last_time = jiffies;
+               count++;
                return 1;
        }
        return 0;
index 00700f7e68376c72d1be595c70b7fb1b7adca1b9..a4c78152b3366568edf0949935765a11a63a355f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/nodemask.h>
 #include <asm/sn/types.h>
 #include <asm/sn/addrs.h>
+#include <asm/sn/sn_feature_sets.h>
 #include <asm/sn/geo.h>
 #include <asm/sn/io.h>
 #include <asm/sn/pcibr_provider.h>
@@ -173,8 +174,8 @@ sn_pcidev_info_get(struct pci_dev *dev)
  */
 static u8 war_implemented = 0;
 
-static void sn_device_fixup_war(u64 nasid, u64 widget, int device,
-                               struct sn_flush_device_common *common)
+static s64 sn_device_fixup_war(u64 nasid, u64 widget, int device,
+                              struct sn_flush_device_common *common)
 {
        struct sn_flush_device_war *war_list;
        struct sn_flush_device_war *dev_entry;
@@ -198,8 +199,9 @@ static void sn_device_fixup_war(u64 nasid, u64 widget, int device,
 
        dev_entry = war_list + device;
        memcpy(common,dev_entry, sizeof(*common));
-
        kfree(war_list);
+
+       return isrv.status;
 }
 
 /*
@@ -279,23 +281,21 @@ static void sn_fixup_ionodes(void)
                                memset(dev_entry->common, 0x0, sizeof(struct
                                                       sn_flush_device_common));
 
-                               status = sal_get_device_dmaflush_list(nasid,
-                                                                       widget,
-                                                                       device,
+                               if (sn_prom_feature_available(
+                                                      PRF_DEVICE_FLUSH_LIST))
+                                       status = sal_get_device_dmaflush_list(
+                                                                         nasid,
+                                                                        widget,
+                                                                        device,
                                                      (u64)(dev_entry->common));
-                               if (status) {
-                                       if (sn_sal_rev() < 0x0450) {
-                                               /* shortlived WAR for older
-                                                * PROM images
-                                                */
-                                               sn_device_fixup_war(nasid,
-                                                                   widget,
-                                                                   device,
+                               else
+                                       status = sn_device_fixup_war(nasid,
+                                                                    widget,
+                                                                    device,
                                                             dev_entry->common);
-                                       }
-                                       else
-                                               BUG();
-                               }
+                               if (status != SALRET_OK)
+                                       panic("SAL call failed: %s\n",
+                                             ia64_sal_strerror(status));
 
                                spin_lock_init(&dev_entry->sfdl_flush_lock);
                        }
index 8d950c778bb6c71a8ef13090f29e4ad7e224973d..36e5437a0fb6bdc281e104340b4b9ec8f4358a3a 100644 (file)
@@ -447,7 +447,7 @@ xpc_allocate_local_msgqueue(struct xpc_channel *ch)
 
                nbytes = nentries * ch->msg_size;
                ch->local_msgqueue = xpc_kmalloc_cacheline_aligned(nbytes,
-                                               (GFP_KERNEL | GFP_DMA),
+                                               GFP_KERNEL,
                                                &ch->local_msgqueue_base);
                if (ch->local_msgqueue == NULL) {
                        continue;
@@ -455,7 +455,7 @@ xpc_allocate_local_msgqueue(struct xpc_channel *ch)
                memset(ch->local_msgqueue, 0, nbytes);
 
                nbytes = nentries * sizeof(struct xpc_notify);
-               ch->notify_queue = kmalloc(nbytes, (GFP_KERNEL | GFP_DMA));
+               ch->notify_queue = kmalloc(nbytes, GFP_KERNEL);
                if (ch->notify_queue == NULL) {
                        kfree(ch->local_msgqueue_base);
                        ch->local_msgqueue = NULL;
@@ -502,7 +502,7 @@ xpc_allocate_remote_msgqueue(struct xpc_channel *ch)
 
                nbytes = nentries * ch->msg_size;
                ch->remote_msgqueue = xpc_kmalloc_cacheline_aligned(nbytes,
-                                               (GFP_KERNEL | GFP_DMA),
+                                               GFP_KERNEL,
                                                &ch->remote_msgqueue_base);
                if (ch->remote_msgqueue == NULL) {
                        continue;
index 9bf9f23b9a1f50b8384127305160779763d48c4b..5a36292388eb79d420db590c0ab0655bd9649afa 100644 (file)
@@ -90,14 +90,14 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size,
         */
        node = pcibus_to_node(pdev->bus);
        if (likely(node >=0)) {
-               struct page *p = alloc_pages_node(node, GFP_ATOMIC, get_order(size));
+               struct page *p = alloc_pages_node(node, flags, get_order(size));
 
                if (likely(p))
                        cpuaddr = page_address(p);
                else
                        return NULL;
        } else
-               cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
+               cpuaddr = (void *)__get_free_pages(flags, get_order(size));
 
        if (unlikely(!cpuaddr))
                return NULL;
index 94ea346b7b4b8b7def5f003d5a4dfe8ce74623b4..1f01b7e2376b97a1f258eb2c0fdcb7abe955d91f 100644 (file)
@@ -313,7 +313,7 @@ static struct platform_device mpsc1_device = {
 };
 #endif
 
-#ifdef CONFIG_MV643XX_ETH
+#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
 static struct resource mv64x60_eth_shared_resources[] = {
        [0] = {
                .name   = "ethernet shared base",
@@ -456,7 +456,7 @@ static struct platform_device *mv64x60_pd_devs[] __initdata = {
        &mpsc0_device,
        &mpsc1_device,
 #endif
-#ifdef CONFIG_MV643XX_ETH
+#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
        &mv64x60_eth_shared_device,
 #endif
 #ifdef CONFIG_MV643XX_ETH_0
index c51d08d218ef9f193538e209b55e6041ca74fa5c..267ec8f6fb585a8d5763f1eea412102686c2bbc3 100644 (file)
@@ -38,7 +38,7 @@
 
 #define curptr      g6
 
-#define NR_SYSCALLS 284      /* Each OS is different... */
+#define NR_SYSCALLS 299      /* Each OS is different... */
 
 /* These are just handy. */
 #define _SV    save    %sp, -STACKFRAME_SZ, %sp
index be2c80932e2673c82f1d7ebbccc15090d5dc6240..8613b3eb877c738ed71adcec2281865bcef924c2 100644 (file)
@@ -323,11 +323,6 @@ static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs)
                case FMOVS:
                case FABSS:
                case FNEGS: TYPE(2,1,0,1,0,0,0); break;
-               default:
-#ifdef DEBUG_MATHEMU
-                       printk("unknown FPop1: %03lx\n",(insn>>5)&0x1ff);
-#endif
-                       break;
                }
        } else if ((insn & 0xc1f80000) == 0x81a80000)   /* FPOP2 */ {
                switch ((insn >> 5) & 0x1ff) {
@@ -337,11 +332,6 @@ static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs)
                case FCMPED: TYPE(3,0,0,2,1,2,1); break;
                case FCMPQ: TYPE(3,0,0,3,1,3,1); break;
                case FCMPEQ: TYPE(3,0,0,3,1,3,1); break;
-               default:
-#ifdef DEBUG_MATHEMU
-                       printk("unknown FPop2: %03lx\n",(insn>>5)&0x1ff);
-#endif
-                       break;
                }
        }
 
index e50e56e4ab61c584a606d52f42fb597c4fcd35fa..12911e7463f22c3b94830fc5d3d3577ff2b91670 100644 (file)
@@ -25,7 +25,7 @@
 
 #define curptr      g6
 
-#define NR_SYSCALLS 284      /* Each OS is different... */
+#define NR_SYSCALLS 299      /* Each OS is different... */
 
        .text
        .align          32
index 9cd272ac3ac10342de0e8ff4f5e0e4c45a860013..60b59375aa78d31f78b832f76928fc6d4447ce72 100644 (file)
@@ -84,7 +84,6 @@ SIGN2(sys32_fadvise64_64, compat_sys_fadvise64_64, %o0, %o5)
 SIGN2(sys32_bdflush, sys_bdflush, %o0, %o1)
 SIGN1(sys32_mlockall, sys_mlockall, %o0)
 SIGN1(sys32_nfsservctl, compat_sys_nfsservctl, %o0)
-SIGN1(sys32_clock_settime, compat_sys_clock_settime, %o1)
 SIGN1(sys32_clock_nanosleep, compat_sys_clock_nanosleep, %o1)
 SIGN1(sys32_timer_settime, compat_sys_timer_settime, %o1)
 SIGN1(sys32_io_submit, compat_sys_io_submit, %o1)
index bf0fc5bfbfbeb7d10563590674c2d80d9326d782..2881faf36635c522d247e8bc6953c7efce8a3248 100644 (file)
@@ -71,7 +71,7 @@ sys_call_table32:
 /*240*/        .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler
        .word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
 /*250*/        .word sys32_mremap, sys32_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl
-       .word sys_ni_syscall, sys32_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep
+       .word sys_ni_syscall, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep
 /*260*/        .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun
        .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy
 /*270*/        .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink
index f16c0d57c552f1fade440fb7a683fa649bc7099f..00d4ddbf980ccdddf23153f3e2758ac72ef90f9a 100644 (file)
@@ -29,11 +29,8 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus)
 
        while (1) {
                ++cfg_num;
-               if (cfg_num >= pci_mmcfg_config_num) {
-                       /* Not found - fall back to type 1. This happens
-                          e.g. on the internal devices of a K8 northbridge. */
-                       return NULL;
-               }
+               if (cfg_num >= pci_mmcfg_config_num)
+                       break;
                cfg = pci_mmcfg_virt[cfg_num].cfg;
                if (cfg->pci_segment_group_number != seg)
                        continue;
@@ -41,6 +38,18 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus)
                    (cfg->end_bus_number >= bus))
                        return pci_mmcfg_virt[cfg_num].virt;
        }
+
+       /* Handle more broken MCFG tables on Asus etc.
+          They only contain a single entry for bus 0-0. Assume
+          this applies to all busses. */
+       cfg = &pci_mmcfg_config[0];
+       if (pci_mmcfg_config_num == 1 &&
+               cfg->pci_segment_group_number == 0 &&
+               (cfg->start_bus_number | cfg->end_bus_number) == 0)
+               return cfg->base_address;
+
+       /* Fall back to type 0 */
+       return 0;
 }
 
 static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
index c9f424d5399c55b588779f252e8bb41b0fe51410..96a61e029ce5e7858d2e024c08eff817b5a998d6 100644 (file)
@@ -139,35 +139,16 @@ static int elevator_attach(request_queue_t *q, struct elevator_type *e,
 
 static char chosen_elevator[16];
 
-static void elevator_setup_default(void)
+static int __init elevator_setup(char *str)
 {
-       struct elevator_type *e;
-
-       /*
-        * If default has not been set, use the compiled-in selection.
-        */
-       if (!chosen_elevator[0])
-               strcpy(chosen_elevator, CONFIG_DEFAULT_IOSCHED);
-
        /*
         * Be backwards-compatible with previous kernels, so users
         * won't get the wrong elevator.
         */
-       if (!strcmp(chosen_elevator, "as"))
+       if (!strcmp(str, "as"))
                strcpy(chosen_elevator, "anticipatory");
-
-       /*
-        * If the given scheduler is not available, fall back to the default
-        */
-       if ((e = elevator_find(chosen_elevator)))
-               elevator_put(e);
        else
-               strcpy(chosen_elevator, CONFIG_DEFAULT_IOSCHED);
-}
-
-static int __init elevator_setup(char *str)
-{
-       strncpy(chosen_elevator, str, sizeof(chosen_elevator) - 1);
+               strncpy(chosen_elevator, str, sizeof(chosen_elevator) - 1);
        return 0;
 }
 
@@ -184,14 +165,16 @@ int elevator_init(request_queue_t *q, char *name)
        q->end_sector = 0;
        q->boundary_rq = NULL;
 
-       elevator_setup_default();
+       if (name && !(e = elevator_get(name)))
+               return -EINVAL;
 
-       if (!name)
-               name = chosen_elevator;
+       if (!e && *chosen_elevator && !(e = elevator_get(chosen_elevator)))
+               printk("I/O scheduler %s not found\n", chosen_elevator);
 
-       e = elevator_get(name);
-       if (!e)
-               return -EINVAL;
+       if (!e && !(e = elevator_get(CONFIG_DEFAULT_IOSCHED))) {
+               printk("Default I/O scheduler not found, using no-op\n");
+               e = elevator_get("noop");
+       }
 
        eq = kmalloc(sizeof(struct elevator_queue), GFP_KERNEL);
        if (!eq) {
@@ -669,8 +652,10 @@ int elv_register(struct elevator_type *e)
        spin_unlock_irq(&elv_list_lock);
 
        printk(KERN_INFO "io scheduler %s registered", e->elevator_name);
-       if (!strcmp(e->elevator_name, chosen_elevator))
-               printk(" (default)");
+       if (!strcmp(e->elevator_name, chosen_elevator) ||
+                       (!*chosen_elevator &&
+                        !strcmp(e->elevator_name, CONFIG_DEFAULT_IOSCHED)))
+                               printk(" (default)");
        printk("\n");
        return 0;
 }
index 8e27d0ab0d7ccefef5a53d42c52978200040ca18..d38b4afa37ef038dd8a7e0472b1150261972bf47 100644 (file)
@@ -304,6 +304,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq)
  * blk_queue_ordered - does this queue support ordered writes
  * @q:        the request queue
  * @ordered:  one of QUEUE_ORDERED_*
+ * @prepare_flush_fn: rq setup helper for cache flush ordered writes
  *
  * Description:
  *   For journalled file systems, doing ordered writes on a commit
@@ -332,6 +333,7 @@ int blk_queue_ordered(request_queue_t *q, unsigned ordered,
                return -EINVAL;
        }
 
+       q->ordered = ordered;
        q->next_ordered = ordered;
        q->prepare_flush_fn = prepare_flush_fn;
 
@@ -662,7 +664,7 @@ EXPORT_SYMBOL(blk_queue_bounce_limit);
  *    Enables a low level driver to set an upper limit on the size of
  *    received requests.
  **/
-void blk_queue_max_sectors(request_queue_t *q, unsigned short max_sectors)
+void blk_queue_max_sectors(request_queue_t *q, unsigned int max_sectors)
 {
        if ((max_sectors << 9) < PAGE_CACHE_SIZE) {
                max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
@@ -2632,6 +2634,7 @@ EXPORT_SYMBOL(blk_put_request);
 /**
  * blk_end_sync_rq - executes a completion event on a request
  * @rq: request to complete
+ * @error: end io status of the request
  */
 void blk_end_sync_rq(struct request *rq, int error)
 {
@@ -3153,7 +3156,7 @@ static int __end_that_request_first(struct request *req, int uptodate,
        if (blk_fs_request(req) && req->rq_disk) {
                const int rw = rq_data_dir(req);
 
-               __disk_stat_add(req->rq_disk, sectors[rw], nr_bytes >> 9);
+               disk_stat_add(req->rq_disk, sectors[rw], nr_bytes >> 9);
        }
 
        total_bytes = bio_nbytes = 0;
index a05fe5843e6c7ee5645d9c5b71572c5d0632d4e6..f04d864770add163a966c2cd947a6ec6d4f345f9 100644 (file)
@@ -14,7 +14,6 @@
  *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
  *  -- verify the 13 conditions and do bulk resets
  *  -- kill last_pipe and simply do two-state clearing on both pipes
- *  -- verify protocol (bulk) from USB descriptors (maybe...)
  *  -- highmem
  *  -- move top_sense and work_bcs into separate allocations (if they survive)
  *     for cache purists and esoteric architectures.
@@ -355,7 +354,7 @@ struct ub_lun {
  * The USB device instance.
  */
 struct ub_dev {
-       spinlock_t lock;
+       spinlock_t *lock;
        atomic_t poison;                /* The USB device is disconnected */
        int openc;                      /* protected by ub_lock! */
                                        /* kref is too implicit for our taste */
@@ -420,11 +419,13 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
 static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
     int stalled_pipe);
 static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
-static void ub_reset_enter(struct ub_dev *sc);
+static void ub_reset_enter(struct ub_dev *sc, int try);
 static void ub_reset_task(void *arg);
 static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
 static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
     struct ub_capacity *ret);
+static int ub_sync_reset(struct ub_dev *sc);
+static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe);
 static int ub_probe_lun(struct ub_dev *sc, int lnum);
 
 /*
@@ -452,6 +453,10 @@ MODULE_DEVICE_TABLE(usb, ub_usb_ids);
 #define UB_MAX_HOSTS  26
 static char ub_hostv[UB_MAX_HOSTS];
 
+#define UB_QLOCK_NUM 5
+static spinlock_t ub_qlockv[UB_QLOCK_NUM];
+static int ub_qlock_next = 0;
+
 static DEFINE_SPINLOCK(ub_lock);       /* Locks globals and ->openc */
 
 /*
@@ -531,7 +536,7 @@ static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr,
                return 0;
 
        cnt = 0;
-       spin_lock_irqsave(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
 
        cnt += sprintf(page + cnt,
            "poison %d reset %d\n",
@@ -579,7 +584,7 @@ static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr,
                if (++nc == SCMD_TRACE_SZ) nc = 0;
        }
 
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
        return cnt;
 }
 
@@ -626,6 +631,24 @@ static void ub_id_put(int id)
        spin_unlock_irqrestore(&ub_lock, flags);
 }
 
+/*
+ * This is necessitated by the fact that blk_cleanup_queue does not
+ * necesserily destroy the queue. Instead, it may merely decrease q->refcnt.
+ * Since our blk_init_queue() passes a spinlock common with ub_dev,
+ * we have life time issues when ub_cleanup frees ub_dev.
+ */
+static spinlock_t *ub_next_lock(void)
+{
+       unsigned long flags;
+       spinlock_t *ret;
+
+       spin_lock_irqsave(&ub_lock, flags);
+       ret = &ub_qlockv[ub_qlock_next];
+       ub_qlock_next = (ub_qlock_next + 1) % UB_QLOCK_NUM;
+       spin_unlock_irqrestore(&ub_lock, flags);
+       return ret;
+}
+
 /*
  * Downcount for deallocation. This rides on two assumptions:
  *  - once something is poisoned, its refcount cannot grow
@@ -961,7 +984,7 @@ static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
        if (atomic_read(&sc->poison))
                return -ENXIO;
 
-       ub_reset_enter(sc);
+       ub_reset_enter(sc, urq->current_try);
 
        if (urq->current_try >= 3)
                return -EIO;
@@ -997,8 +1020,6 @@ static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
  * No exceptions.
  *
  * Host is assumed locked.
- *
- * XXX We only support Bulk for the moment.
  */
 static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 {
@@ -1083,9 +1104,10 @@ static void ub_urb_timeout(unsigned long arg)
        struct ub_dev *sc = (struct ub_dev *) arg;
        unsigned long flags;
 
-       spin_lock_irqsave(&sc->lock, flags);
-       usb_unlink_urb(&sc->work_urb);
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
+       if (!ub_is_completed(&sc->work_done))
+               usb_unlink_urb(&sc->work_urb);
+       spin_unlock_irqrestore(sc->lock, flags);
 }
 
 /*
@@ -1108,10 +1130,9 @@ static void ub_scsi_action(unsigned long _dev)
        struct ub_dev *sc = (struct ub_dev *) _dev;
        unsigned long flags;
 
-       spin_lock_irqsave(&sc->lock, flags);
-       del_timer(&sc->work_timer);
+       spin_lock_irqsave(sc->lock, flags);
        ub_scsi_dispatch(sc);
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 }
 
 static void ub_scsi_dispatch(struct ub_dev *sc)
@@ -1133,6 +1154,7 @@ static void ub_scsi_dispatch(struct ub_dev *sc)
                } else {
                        if (!ub_is_completed(&sc->work_done))
                                break;
+                       del_timer(&sc->work_timer);
                        ub_scsi_urb_compl(sc, cmd);
                }
        }
@@ -1680,16 +1702,18 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
 
 /*
  * Reset management
+ * XXX Move usb_reset_device to khubd. Hogging kevent is not a good thing.
+ * XXX Make usb_sync_reset asynchronous.
  */
 
-static void ub_reset_enter(struct ub_dev *sc)
+static void ub_reset_enter(struct ub_dev *sc, int try)
 {
 
        if (sc->reset) {
                /* This happens often on multi-LUN devices. */
                return;
        }
-       sc->reset = 1;
+       sc->reset = try + 1;
 
 #if 0 /* Not needed because the disconnect waits for us. */
        unsigned long flags;
@@ -1727,6 +1751,11 @@ static void ub_reset_task(void *arg)
        if (atomic_read(&sc->poison)) {
                printk(KERN_NOTICE "%s: Not resetting disconnected device\n",
                    sc->name); /* P3 This floods. Remove soon. XXX */
+       } else if ((sc->reset & 1) == 0) {
+               ub_sync_reset(sc);
+               msleep(700);    /* usb-storage sleeps 6s (!) */
+               ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
+               ub_probe_clear_stall(sc, sc->send_bulk_pipe);
        } else if (sc->dev->actconfig->desc.bNumInterfaces != 1) {
                printk(KERN_NOTICE "%s: Not resetting multi-interface device\n",
                    sc->name); /* P3 This floods. Remove soon. XXX */
@@ -1754,7 +1783,7 @@ static void ub_reset_task(void *arg)
         * queues of resets or anything. We do need a spinlock though,
         * to interact with block layer.
         */
-       spin_lock_irqsave(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
        sc->reset = 0;
        tasklet_schedule(&sc->tasklet);
        list_for_each(p, &sc->luns) {
@@ -1762,7 +1791,7 @@ static void ub_reset_task(void *arg)
                blk_start_queue(lun->disk->queue);
        }
        wake_up(&sc->reset_wait);
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 }
 
 /*
@@ -1990,11 +2019,11 @@ static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
        cmd->done = ub_probe_done;
        cmd->back = &compl;
 
-       spin_lock_irqsave(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
        cmd->tag = sc->tagcnt++;
 
        rc = ub_submit_scsi(sc, cmd);
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 
        if (rc != 0) {
                printk("ub: testing ready: submit error (%d)\n", rc); /* P3 */
@@ -2052,11 +2081,11 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
        cmd->done = ub_probe_done;
        cmd->back = &compl;
 
-       spin_lock_irqsave(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
        cmd->tag = sc->tagcnt++;
 
        rc = ub_submit_scsi(sc, cmd);
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 
        if (rc != 0) {
                printk("ub: reading capacity: submit error (%d)\n", rc); /* P3 */
@@ -2117,6 +2146,52 @@ static void ub_probe_timeout(unsigned long arg)
        complete(cop);
 }
 
+/*
+ * Reset with a Bulk reset.
+ */
+static int ub_sync_reset(struct ub_dev *sc)
+{
+       int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;
+       struct usb_ctrlrequest *cr;
+       struct completion compl;
+       struct timer_list timer;
+       int rc;
+
+       init_completion(&compl);
+
+       cr = &sc->work_cr;
+       cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+       cr->bRequest = US_BULK_RESET_REQUEST;
+       cr->wValue = cpu_to_le16(0);
+       cr->wIndex = cpu_to_le16(ifnum);
+       cr->wLength = cpu_to_le16(0);
+
+       usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
+           (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
+       sc->work_urb.actual_length = 0;
+       sc->work_urb.error_count = 0;
+       sc->work_urb.status = 0;
+
+       if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
+               printk(KERN_WARNING
+                    "%s: Unable to submit a bulk reset (%d)\n", sc->name, rc);
+               return rc;
+       }
+
+       init_timer(&timer);
+       timer.function = ub_probe_timeout;
+       timer.data = (unsigned long) &compl;
+       timer.expires = jiffies + UB_CTRL_TIMEOUT;
+       add_timer(&timer);
+
+       wait_for_completion(&compl);
+
+       del_timer_sync(&timer);
+       usb_kill_urb(&sc->work_urb);
+
+       return sc->work_urb.status;
+}
+
 /*
  * Get number of LUNs by the way of Bulk GetMaxLUN command.
  */
@@ -2333,7 +2408,7 @@ static int ub_probe(struct usb_interface *intf,
        if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
                goto err_core;
        memset(sc, 0, sizeof(struct ub_dev));
-       spin_lock_init(&sc->lock);
+       sc->lock = ub_next_lock();
        INIT_LIST_HEAD(&sc->luns);
        usb_init_urb(&sc->work_urb);
        tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
@@ -2483,7 +2558,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
        disk->driverfs_dev = &sc->intf->dev;
 
        rc = -ENOMEM;
-       if ((q = blk_init_queue(ub_request_fn, &sc->lock)) == NULL)
+       if ((q = blk_init_queue(ub_request_fn, sc->lock)) == NULL)
                goto err_blkqinit;
 
        disk->queue = q;
@@ -2554,7 +2629,7 @@ static void ub_disconnect(struct usb_interface *intf)
         * and the whole queue drains. So, we just use this code to
         * print warnings.
         */
-       spin_lock_irqsave(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
        {
                struct ub_scsi_cmd *cmd;
                int cnt = 0;
@@ -2571,7 +2646,7 @@ static void ub_disconnect(struct usb_interface *intf)
                            "%d was queued after shutdown\n", sc->name, cnt);
                }
        }
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 
        /*
         * Unregister the upper layer.
@@ -2590,19 +2665,15 @@ static void ub_disconnect(struct usb_interface *intf)
        }
 
        /*
-        * Taking a lock on a structure which is about to be freed
-        * is very nonsensual. Here it is largely a way to do a debug freeze,
-        * and a bracket which shows where the nonsensual code segment ends.
-        *
         * Testing for -EINPROGRESS is always a bug, so we are bending
         * the rules a little.
         */
-       spin_lock_irqsave(&sc->lock, flags);
+       spin_lock_irqsave(sc->lock, flags);
        if (sc->work_urb.status == -EINPROGRESS) {      /* janitors: ignore */
                printk(KERN_WARNING "%s: "
                    "URB is active after disconnect\n", sc->name);
        }
-       spin_unlock_irqrestore(&sc->lock, flags);
+       spin_unlock_irqrestore(sc->lock, flags);
 
        /*
         * There is virtually no chance that other CPU runs times so long
@@ -2636,6 +2707,10 @@ static struct usb_driver ub_driver = {
 static int __init ub_init(void)
 {
        int rc;
+       int i;
+
+       for (i = 0; i < UB_QLOCK_NUM; i++)
+               spin_lock_init(&ub_qlockv[i]);
 
        if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
                goto err_regblkdev;
index 810679dcbbb0cb006c619af994bb91f6e60cd7a0..9964c508c1113e4d2a4540427982e1c791c210d7 100644 (file)
@@ -600,6 +600,26 @@ static void __devexit agp_amd64_remove(struct pci_dev *pdev)
        agp_put_bridge(bridge);
 }
 
+#ifdef CONFIG_PM
+
+static int agp_amd64_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       pci_save_state(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+static int agp_amd64_resume(struct pci_dev *pdev)
+{
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+
+       return amd_8151_configure();
+}
+
+#endif /* CONFIG_PM */
+
 static struct pci_device_id agp_amd64_pci_table[] = {
        {
        .class          = (PCI_CLASS_BRIDGE_HOST << 8),
@@ -718,6 +738,10 @@ static struct pci_driver agp_amd64_pci_driver = {
        .id_table       = agp_amd64_pci_table,
        .probe          = agp_amd64_probe,
        .remove         = agp_amd64_remove,
+#ifdef CONFIG_PM
+       .suspend        = agp_amd64_suspend,
+       .resume         = agp_amd64_resume,
+#endif
 };
 
 
index 53372a83b6758420e7c586cdd20ceb79e412050b..5b74c36c116c7e112c0265ddf147e249586d8981 100644 (file)
@@ -244,6 +244,22 @@ static int ati_configure(void)
 }
 
 
+#ifdef CONFIG_PM
+static int agp_ati_resume(struct pci_dev *dev)
+{
+       pci_restore_state(dev);
+
+       return ati_configure();
+}
+
+static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state)
+{
+       pci_save_state(dev);
+
+       return 0;
+}
+#endif
+
 /*
  *Since we don't need contigious memory we just try
  * to get the gatt table once
@@ -525,6 +541,10 @@ static struct pci_driver agp_ati_pci_driver = {
        .id_table       = agp_ati_pci_table,
        .probe          = agp_ati_probe,
        .remove         = agp_ati_remove,
+#ifdef CONFIG_PM
+       .resume         = agp_ati_resume,
+       .suspend        = agp_ati_suspend,
+#endif
 };
 
 static int __init agp_ati_init(void)
index 17f520c9d4714aa90a145f200c31675b38699882..97eeb2345b18ad897c429196530ce7d49dec3980 100644 (file)
@@ -592,7 +592,7 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma)
        struct agp_file_private *priv = file->private_data;
        struct agp_kern_info kerninfo;
 
-       down(&(agp_fe.agp_mutex));
+       mutex_lock(&(agp_fe.agp_mutex));
 
        if (agp_fe.backend_acquired != TRUE)
                goto out_eperm;
@@ -627,7 +627,7 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma)
                                            size, vma->vm_page_prot)) {
                        goto out_again;
                }
-               up(&(agp_fe.agp_mutex));
+               mutex_unlock(&(agp_fe.agp_mutex));
                return 0;
        }
 
@@ -643,20 +643,20 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma)
                                            size, vma->vm_page_prot)) {
                        goto out_again;
                }
-               up(&(agp_fe.agp_mutex));
+               mutex_unlock(&(agp_fe.agp_mutex));
                return 0;
        }
 
 out_eperm:
-       up(&(agp_fe.agp_mutex));
+       mutex_unlock(&(agp_fe.agp_mutex));
        return -EPERM;
 
 out_inval:
-       up(&(agp_fe.agp_mutex));
+       mutex_unlock(&(agp_fe.agp_mutex));
        return -EINVAL;
 
 out_again:
-       up(&(agp_fe.agp_mutex));
+       mutex_unlock(&(agp_fe.agp_mutex));
        return -EAGAIN;
 }
 
@@ -664,7 +664,7 @@ static int agp_release(struct inode *inode, struct file *file)
 {
        struct agp_file_private *priv = file->private_data;
 
-       down(&(agp_fe.agp_mutex));
+       mutex_lock(&(agp_fe.agp_mutex));
 
        DBG("priv=%p", priv);
 
@@ -687,7 +687,7 @@ static int agp_release(struct inode *inode, struct file *file)
        agp_remove_file_private(priv);
        kfree(priv);
        file->private_data = NULL;
-       up(&(agp_fe.agp_mutex));
+       mutex_unlock(&(agp_fe.agp_mutex));
        return 0;
 }
 
@@ -698,7 +698,7 @@ static int agp_open(struct inode *inode, struct file *file)
        struct agp_client *client;
        int rc = -ENXIO;
 
-       down(&(agp_fe.agp_mutex));
+       mutex_lock(&(agp_fe.agp_mutex));
 
        if (minor != AGPGART_MINOR)
                goto err_out;
@@ -723,13 +723,13 @@ static int agp_open(struct inode *inode, struct file *file)
        file->private_data = (void *) priv;
        agp_insert_file_private(priv);
        DBG("private=%p, client=%p", priv, client);
-       up(&(agp_fe.agp_mutex));
+       mutex_unlock(&(agp_fe.agp_mutex));
        return 0;
 
 err_out_nomem:
        rc = -ENOMEM;
 err_out:
-       up(&(agp_fe.agp_mutex));
+       mutex_unlock(&(agp_fe.agp_mutex));
        return rc;
 }
 
@@ -985,7 +985,7 @@ static int agp_ioctl(struct inode *inode, struct file *file,
        int ret_val = -ENOTTY;
 
        DBG("priv=%p, cmd=%x", curr_priv, cmd);
-       down(&(agp_fe.agp_mutex));
+       mutex_lock(&(agp_fe.agp_mutex));
 
        if ((agp_fe.current_controller == NULL) &&
            (cmd != AGPIOC_ACQUIRE)) {
@@ -1055,7 +1055,7 @@ static int agp_ioctl(struct inode *inode, struct file *file,
 
 ioctl_out:
        DBG("ioctl returns %d\n", ret_val);
-       up(&(agp_fe.agp_mutex));
+       mutex_unlock(&(agp_fe.agp_mutex));
        return ret_val;
 }
 
@@ -1081,7 +1081,7 @@ static struct miscdevice agp_miscdev =
 int agp_frontend_initialize(void)
 {
        memset(&agp_fe, 0, sizeof(struct agp_front_data));
-       sema_init(&(agp_fe.agp_mutex), 1);
+       mutex_init(&(agp_fe.agp_mutex));
 
        if (misc_register(&agp_miscdev)) {
                printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR);
index e7bed5047dcc9b8da874ef2e4007e795cc847a87..631531fd97a58dab4b619aa0c0ecb9728ddb3f41 100644 (file)
@@ -422,7 +422,8 @@ static void intel_i830_init_gtt_entries(void)
                        /* Check it's really I915G */
                        if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
                            agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB)
+                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
+                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB)
                                gtt_entries = MB(48) - KB(size);
                        else
                                gtt_entries = 0;
@@ -431,7 +432,8 @@ static void intel_i830_init_gtt_entries(void)
                        /* Check it's really I915G */
                        if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
                            agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
-                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB)
+                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
+                           agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB)
                                gtt_entries = MB(64) - KB(size);
                        else
                                gtt_entries = 0;
@@ -1681,6 +1683,14 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                }
                name = "945G";
                break;
+       case PCI_DEVICE_ID_INTEL_82945GM_HB:
+               if (find_i830(PCI_DEVICE_ID_INTEL_82945GM_IG)) {
+                       bridge->driver = &intel_915_driver;
+               } else {
+                       bridge->driver = &intel_845_driver;
+               }
+               name = "945GM";
+               break;
        case PCI_DEVICE_ID_INTEL_7505_0:
                bridge->driver = &intel_7505_driver;
                name = "E7505";
@@ -1821,6 +1831,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
        ID(PCI_DEVICE_ID_INTEL_82915G_HB),
        ID(PCI_DEVICE_ID_INTEL_82915GM_HB),
        ID(PCI_DEVICE_ID_INTEL_82945G_HB),
+       ID(PCI_DEVICE_ID_INTEL_82945GM_HB),
        { }
 };
 
index 40083241804eee1b48f09902e7c67a82d0cf7276..7c14a096b85eea4a3fc793ef329324989a27a77f 100644 (file)
@@ -218,10 +218,8 @@ static int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge,
                        master[cdev].rq *= (1 << (master[cdev].y - 1));
 
                tot_rq += master[cdev].rq;
-
-               if (cdev == ndevs-1)
-                       master[cdev].n += rem;
        }
+       master[ndevs-1].n += rem;
 
        /* Figure the number of isochronous and asynchronous RQ slots the
         * target is providing. */
index 277a843a87a60bc3cc001fe10529d7c053e8a7f5..7a511479ae29b615e0d8fe1fcfdd223212a7e2a8 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/cpu.h>
 #include <linux/completion.h>
+#include <linux/mutex.h>
 
 #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "cpufreq-core", msg)
 
@@ -55,7 +56,7 @@ static DECLARE_RWSEM          (cpufreq_notifier_rwsem);
 
 
 static LIST_HEAD(cpufreq_governor_list);
-static DECLARE_MUTEX           (cpufreq_governor_sem);
+static DEFINE_MUTEX            (cpufreq_governor_mutex);
 
 struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu)
 {
@@ -297,18 +298,18 @@ static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
                return -EINVAL;
        } else {
                struct cpufreq_governor *t;
-               down(&cpufreq_governor_sem);
+               mutex_lock(&cpufreq_governor_mutex);
                if (!cpufreq_driver || !cpufreq_driver->target)
                        goto out;
                list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
                        if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) {
                                *governor = t;
-                               up(&cpufreq_governor_sem);
+                               mutex_unlock(&cpufreq_governor_mutex);
                                return 0;
                        }
                }
        out:
-               up(&cpufreq_governor_sem);
+               mutex_unlock(&cpufreq_governor_mutex);
        }
        return -EINVAL;
 }
@@ -600,7 +601,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        policy->cpu = cpu;
        policy->cpus = cpumask_of_cpu(cpu);
 
-       init_MUTEX_LOCKED(&policy->lock);
+       mutex_init(&policy->lock);
+       mutex_lock(&policy->lock);
        init_completion(&policy->kobj_unregister);
        INIT_WORK(&policy->update, handle_update, (void *)(long)cpu);
 
@@ -610,6 +612,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        ret = cpufreq_driver->init(policy);
        if (ret) {
                dprintk("initialization failed\n");
+               mutex_unlock(&policy->lock);
                goto err_out;
        }
 
@@ -621,9 +624,10 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
 
        ret = kobject_register(&policy->kobj);
-       if (ret)
+       if (ret) {
+               mutex_unlock(&policy->lock);
                goto err_out_driver_exit;
-
+       }
        /* set up files for this cpu device */
        drv_attr = cpufreq_driver->attr;
        while ((drv_attr) && (*drv_attr)) {
@@ -641,7 +645,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
        policy->governor = NULL; /* to assure that the starting sequence is
                                  * run in cpufreq_set_policy */
-       up(&policy->lock);
+       mutex_unlock(&policy->lock);
        
        /* set default policy */
        
@@ -762,10 +766,10 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 #endif
 
-       down(&data->lock);
+       mutex_lock(&data->lock);
        if (cpufreq_driver->target)
                __cpufreq_governor(data, CPUFREQ_GOV_STOP);
-       up(&data->lock);
+       mutex_unlock(&data->lock);
 
        kobject_unregister(&data->kobj);
 
@@ -834,9 +838,9 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
        unsigned int ret = 0;
 
        if (policy) {
-               down(&policy->lock);
+               mutex_lock(&policy->lock);
                ret = policy->cur;
-               up(&policy->lock);
+               mutex_unlock(&policy->lock);
                cpufreq_cpu_put(policy);
        }
 
@@ -862,7 +866,7 @@ unsigned int cpufreq_get(unsigned int cpu)
        if (!cpufreq_driver->get)
                goto out;
 
-       down(&policy->lock);
+       mutex_lock(&policy->lock);
 
        ret = cpufreq_driver->get(cpu);
 
@@ -875,7 +879,7 @@ unsigned int cpufreq_get(unsigned int cpu)
                }
        }
 
-       up(&policy->lock);
+       mutex_unlock(&policy->lock);
 
  out:
        cpufreq_cpu_put(policy);
@@ -1158,11 +1162,11 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
        if (!policy)
                return -EINVAL;
 
-       down(&policy->lock);
+       mutex_lock(&policy->lock);
 
        ret = __cpufreq_driver_target(policy, target_freq, relation);
 
-       up(&policy->lock);
+       mutex_unlock(&policy->lock);
 
        cpufreq_cpu_put(policy);
 
@@ -1199,9 +1203,9 @@ int cpufreq_governor(unsigned int cpu, unsigned int event)
        if (!policy)
                return -EINVAL;
 
-       down(&policy->lock);
+       mutex_lock(&policy->lock);
        ret = __cpufreq_governor(policy, event);
-       up(&policy->lock);
+       mutex_unlock(&policy->lock);
 
        cpufreq_cpu_put(policy);
 
@@ -1217,17 +1221,17 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
        if (!governor)
                return -EINVAL;
 
-       down(&cpufreq_governor_sem);
+       mutex_lock(&cpufreq_governor_mutex);
        
        list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
                if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) {
-                       up(&cpufreq_governor_sem);
+                       mutex_unlock(&cpufreq_governor_mutex);
                        return -EBUSY;
                }
        }
        list_add(&governor->governor_list, &cpufreq_governor_list);
 
-       up(&cpufreq_governor_sem);
+       mutex_unlock(&cpufreq_governor_mutex);
 
        return 0;
 }
@@ -1239,9 +1243,9 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
        if (!governor)
                return;
 
-       down(&cpufreq_governor_sem);
+       mutex_lock(&cpufreq_governor_mutex);
        list_del(&governor->governor_list);
-       up(&cpufreq_governor_sem);
+       mutex_unlock(&cpufreq_governor_mutex);
        return;
 }
 EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
@@ -1268,9 +1272,9 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
        if (!cpu_policy)
                return -EINVAL;
 
-       down(&cpu_policy->lock);
+       mutex_lock(&cpu_policy->lock);
        memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy));
-       up(&cpu_policy->lock);
+       mutex_unlock(&cpu_policy->lock);
 
        cpufreq_cpu_put(cpu_policy);
 
@@ -1382,7 +1386,7 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
                return -EINVAL;
 
        /* lock this CPU */
-       down(&data->lock);
+       mutex_lock(&data->lock);
 
        ret = __cpufreq_set_policy(data, policy);
        data->user_policy.min = data->min;
@@ -1390,7 +1394,7 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
        data->user_policy.policy = data->policy;
        data->user_policy.governor = data->governor;
 
-       up(&data->lock);
+       mutex_unlock(&data->lock);
        cpufreq_cpu_put(data);
 
        return ret;
@@ -1414,7 +1418,7 @@ int cpufreq_update_policy(unsigned int cpu)
        if (!data)
                return -ENODEV;
 
-       down(&data->lock);
+       mutex_lock(&data->lock);
 
        dprintk("updating policy for CPU %u\n", cpu);
        memcpy(&policy, 
@@ -1425,9 +1429,17 @@ int cpufreq_update_policy(unsigned int cpu)
        policy.policy = data->user_policy.policy;
        policy.governor = data->user_policy.governor;
 
+       /* BIOS might change freq behind our back
+         -> ask driver for current freq and notify governors about a change */
+       if (cpufreq_driver->get) {
+               policy.cur = cpufreq_driver->get(cpu);
+               if (data->cur != policy.cur)
+                       cpufreq_out_of_sync(cpu, data->cur, policy.cur);
+       }
+
        ret = __cpufreq_set_policy(data, &policy);
 
-       up(&data->lock);
+       mutex_unlock(&data->lock);
 
        cpufreq_cpu_put(data);
        return ret;
index 39543a2bed0f43c232e724ce809f1c89d438f6e1..ac38766b2583eec5b5db349b7227e443d6b1177c 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/jiffies.h>
 #include <linux/kernel_stat.h>
 #include <linux/percpu.h>
-
+#include <linux/mutex.h>
 /*
  * dbs is used in this file as a shortform for demandbased switching
  * It helps to keep variable names smaller, simpler
@@ -71,7 +71,7 @@ static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
 
 static unsigned int dbs_enable;        /* number of CPUs using this policy */
 
-static DECLARE_MUTEX   (dbs_sem);
+static DEFINE_MUTEX    (dbs_mutex);
 static DECLARE_WORK    (dbs_work, do_dbs_timer, NULL);
 
 struct dbs_tuners {
@@ -139,9 +139,9 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
        if (ret != 1 )
                return -EINVAL;
 
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        dbs_tuners_ins.sampling_down_factor = input;
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 
        return count;
 }
@@ -153,14 +153,14 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
        int ret;
        ret = sscanf (buf, "%u", &input);
 
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) {
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                return -EINVAL;
        }
 
        dbs_tuners_ins.sampling_rate = input;
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 
        return count;
 }
@@ -172,16 +172,16 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
        int ret;
        ret = sscanf (buf, "%u", &input);
 
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || 
                        input < MIN_FREQUENCY_UP_THRESHOLD ||
                        input <= dbs_tuners_ins.down_threshold) {
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                return -EINVAL;
        }
 
        dbs_tuners_ins.up_threshold = input;
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 
        return count;
 }
@@ -193,16 +193,16 @@ static ssize_t store_down_threshold(struct cpufreq_policy *unused,
        int ret;
        ret = sscanf (buf, "%u", &input);
 
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD || 
                        input < MIN_FREQUENCY_DOWN_THRESHOLD ||
                        input >= dbs_tuners_ins.up_threshold) {
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                return -EINVAL;
        }
 
        dbs_tuners_ins.down_threshold = input;
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 
        return count;
 }
@@ -222,9 +222,9 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
        if ( input > 1 )
                input = 1;
        
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                return count;
        }
        dbs_tuners_ins.ignore_nice = input;
@@ -236,7 +236,7 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
                j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
                j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
        }
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 
        return count;
 }
@@ -257,9 +257,9 @@ static ssize_t store_freq_step(struct cpufreq_policy *policy,
        
        /* no need to test here if freq_step is zero as the user might actually
         * want this, they would be crazy though :) */
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        dbs_tuners_ins.freq_step = input;
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 
        return count;
 }
@@ -444,12 +444,12 @@ static void dbs_check_cpu(int cpu)
 static void do_dbs_timer(void *data)
 { 
        int i;
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        for_each_online_cpu(i)
                dbs_check_cpu(i);
        schedule_delayed_work(&dbs_work, 
                        usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 } 
 
 static inline void dbs_timer_init(void)
@@ -487,7 +487,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                if (this_dbs_info->enable) /* Already enabled */
                        break;
                 
-               down(&dbs_sem);
+               mutex_lock(&dbs_mutex);
                for_each_cpu_mask(j, policy->cpus) {
                        struct cpu_dbs_info_s *j_dbs_info;
                        j_dbs_info = &per_cpu(cpu_dbs_info, j);
@@ -521,11 +521,11 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        dbs_timer_init();
                }
                
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                break;
 
        case CPUFREQ_GOV_STOP:
-               down(&dbs_sem);
+               mutex_lock(&dbs_mutex);
                this_dbs_info->enable = 0;
                sysfs_remove_group(&policy->kobj, &dbs_attr_group);
                dbs_enable--;
@@ -536,12 +536,12 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                if (dbs_enable == 0) 
                        dbs_timer_exit();
                
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
 
                break;
 
        case CPUFREQ_GOV_LIMITS:
-               down(&dbs_sem);
+               mutex_lock(&dbs_mutex);
                if (policy->max < this_dbs_info->cur_policy->cur)
                        __cpufreq_driver_target(
                                        this_dbs_info->cur_policy,
@@ -550,7 +550,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        __cpufreq_driver_target(
                                        this_dbs_info->cur_policy,
                                        policy->min, CPUFREQ_RELATION_L);
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                break;
        }
        return 0;
index e69fd8dd1f1cb7bf6042a878b2545a714c7df133..9ee9411f186f9b8738f4a7320991f058576733d7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/jiffies.h>
 #include <linux/kernel_stat.h>
 #include <linux/percpu.h>
+#include <linux/mutex.h>
 
 /*
  * dbs is used in this file as a shortform for demandbased switching
@@ -70,7 +71,7 @@ static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
 
 static unsigned int dbs_enable;        /* number of CPUs using this policy */
 
-static DECLARE_MUTEX   (dbs_sem);
+static DEFINE_MUTEX    (dbs_mutex);
 static DECLARE_WORK    (dbs_work, do_dbs_timer, NULL);
 
 struct dbs_tuners {
@@ -136,9 +137,9 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
        if (input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
                return -EINVAL;
 
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        dbs_tuners_ins.sampling_down_factor = input;
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 
        return count;
 }
@@ -150,14 +151,14 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
        int ret;
        ret = sscanf (buf, "%u", &input);
 
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) {
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                return -EINVAL;
        }
 
        dbs_tuners_ins.sampling_rate = input;
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 
        return count;
 }
@@ -169,15 +170,15 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
        int ret;
        ret = sscanf (buf, "%u", &input);
 
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || 
                        input < MIN_FREQUENCY_UP_THRESHOLD) {
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                return -EINVAL;
        }
 
        dbs_tuners_ins.up_threshold = input;
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 
        return count;
 }
@@ -197,9 +198,9 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
        if ( input > 1 )
                input = 1;
        
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                return count;
        }
        dbs_tuners_ins.ignore_nice = input;
@@ -211,7 +212,7 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
                j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
                j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
        }
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 
        return count;
 }
@@ -356,12 +357,12 @@ static void dbs_check_cpu(int cpu)
 static void do_dbs_timer(void *data)
 { 
        int i;
-       down(&dbs_sem);
+       mutex_lock(&dbs_mutex);
        for_each_online_cpu(i)
                dbs_check_cpu(i);
        schedule_delayed_work(&dbs_work, 
                        usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
-       up(&dbs_sem);
+       mutex_unlock(&dbs_mutex);
 } 
 
 static inline void dbs_timer_init(void)
@@ -399,7 +400,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                if (this_dbs_info->enable) /* Already enabled */
                        break;
                 
-               down(&dbs_sem);
+               mutex_lock(&dbs_mutex);
                for_each_cpu_mask(j, policy->cpus) {
                        struct cpu_dbs_info_s *j_dbs_info;
                        j_dbs_info = &per_cpu(cpu_dbs_info, j);
@@ -435,11 +436,11 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        dbs_timer_init();
                }
                
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                break;
 
        case CPUFREQ_GOV_STOP:
-               down(&dbs_sem);
+               mutex_lock(&dbs_mutex);
                this_dbs_info->enable = 0;
                sysfs_remove_group(&policy->kobj, &dbs_attr_group);
                dbs_enable--;
@@ -450,12 +451,12 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                if (dbs_enable == 0) 
                        dbs_timer_exit();
                
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
 
                break;
 
        case CPUFREQ_GOV_LIMITS:
-               down(&dbs_sem);
+               mutex_lock(&dbs_mutex);
                if (policy->max < this_dbs_info->cur_policy->cur)
                        __cpufreq_driver_target(
                                        this_dbs_info->cur_policy,
@@ -464,7 +465,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                        __cpufreq_driver_target(
                                        this_dbs_info->cur_policy,
                                        policy->min, CPUFREQ_RELATION_L);
-               up(&dbs_sem);
+               mutex_unlock(&dbs_mutex);
                break;
        }
        return 0;
index d32bf3593cd31433a40f7a1f70f839a1153e0a63..92a0be22a2a95bd92dd19c4c152880608910716d 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  *  linux/drivers/cpufreq/cpufreq_userspace.c
  *
@@ -21,6 +22,7 @@
 #include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/sysfs.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 
@@ -33,9 +35,8 @@ static unsigned int   cpu_min_freq[NR_CPUS];
 static unsigned int    cpu_cur_freq[NR_CPUS]; /* current CPU freq */
 static unsigned int    cpu_set_freq[NR_CPUS]; /* CPU freq desired by userspace */
 static unsigned int    cpu_is_managed[NR_CPUS];
-static struct cpufreq_policy current_policy[NR_CPUS];
 
-static DECLARE_MUTEX   (userspace_sem); 
+static DEFINE_MUTEX    (userspace_mutex);
 
 #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg)
 
@@ -64,35 +65,34 @@ static struct notifier_block userspace_cpufreq_notifier_block = {
  *
  * Sets the CPU frequency to freq.
  */
-static int cpufreq_set(unsigned int freq, unsigned int cpu)
+static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy)
 {
        int ret = -EINVAL;
 
-       dprintk("cpufreq_set for cpu %u, freq %u kHz\n", cpu, freq);
+       dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
 
-       down(&userspace_sem);
-       if (!cpu_is_managed[cpu])
+       mutex_lock(&userspace_mutex);
+       if (!cpu_is_managed[policy->cpu])
                goto err;
 
-       cpu_set_freq[cpu] = freq;
+       cpu_set_freq[policy->cpu] = freq;
 
-       if (freq < cpu_min_freq[cpu])
-               freq = cpu_min_freq[cpu];
-       if (freq > cpu_max_freq[cpu])
-               freq = cpu_max_freq[cpu];
+       if (freq < cpu_min_freq[policy->cpu])
+               freq = cpu_min_freq[policy->cpu];
+       if (freq > cpu_max_freq[policy->cpu])
+               freq = cpu_max_freq[policy->cpu];
 
        /*
         * We're safe from concurrent calls to ->target() here
-        * as we hold the userspace_sem lock. If we were calling
+        * as we hold the userspace_mutex lock. If we were calling
         * cpufreq_driver_target, a deadlock situation might occur:
-        * A: cpufreq_set (lock userspace_sem) -> cpufreq_driver_target(lock policy->lock)
-        * B: cpufreq_set_policy(lock policy->lock) -> __cpufreq_governor -> cpufreq_governor_userspace (lock userspace_sem)
+        * A: cpufreq_set (lock userspace_mutex) -> cpufreq_driver_target(lock policy->lock)
+        * B: cpufreq_set_policy(lock policy->lock) -> __cpufreq_governor -> cpufreq_governor_userspace (lock userspace_mutex)
         */
-       ret = __cpufreq_driver_target(&current_policy[cpu], freq, 
-             CPUFREQ_RELATION_L);
+       ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
 
  err:
-       up(&userspace_sem);
+       mutex_unlock(&userspace_mutex);
        return ret;
 }
 
@@ -113,7 +113,7 @@ store_speed (struct cpufreq_policy *policy, const char *buf, size_t count)
        if (ret != 1)
                return -EINVAL;
 
-       cpufreq_set(freq, policy->cpu);
+       cpufreq_set(freq, policy);
 
        return count;
 }
@@ -134,44 +134,48 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
                if (!cpu_online(cpu))
                        return -EINVAL;
                BUG_ON(!policy->cur);
-               down(&userspace_sem);
+               mutex_lock(&userspace_mutex);
                cpu_is_managed[cpu] = 1;                
                cpu_min_freq[cpu] = policy->min;
                cpu_max_freq[cpu] = policy->max;
                cpu_cur_freq[cpu] = policy->cur;
                cpu_set_freq[cpu] = policy->cur;
                sysfs_create_file (&policy->kobj, &freq_attr_scaling_setspeed.attr);
-               memcpy (&current_policy[cpu], policy, sizeof(struct cpufreq_policy));
                dprintk("managing cpu %u started (%u - %u kHz, currently %u kHz)\n", cpu, cpu_min_freq[cpu], cpu_max_freq[cpu], cpu_cur_freq[cpu]);
-               up(&userspace_sem);
+               mutex_unlock(&userspace_mutex);
                break;
        case CPUFREQ_GOV_STOP:
-               down(&userspace_sem);
+               mutex_lock(&userspace_mutex);
                cpu_is_managed[cpu] = 0;
                cpu_min_freq[cpu] = 0;
                cpu_max_freq[cpu] = 0;
                cpu_set_freq[cpu] = 0;
                sysfs_remove_file (&policy->kobj, &freq_attr_scaling_setspeed.attr);
                dprintk("managing cpu %u stopped\n", cpu);
-               up(&userspace_sem);
+               mutex_unlock(&userspace_mutex);
                break;
        case CPUFREQ_GOV_LIMITS:
-               down(&userspace_sem);
-               cpu_min_freq[cpu] = policy->min;
-               cpu_max_freq[cpu] = policy->max;
-               dprintk("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", cpu, cpu_min_freq[cpu], cpu_max_freq[cpu], cpu_cur_freq[cpu], cpu_set_freq[cpu]);
+               mutex_lock(&userspace_mutex);
+               dprintk("limit event for cpu %u: %u - %u kHz,"
+                       "currently %u kHz, last set to %u kHz\n",
+                       cpu, policy->min, policy->max,
+                       cpu_cur_freq[cpu], cpu_set_freq[cpu]);
                if (policy->max < cpu_set_freq[cpu]) {
-                       __cpufreq_driver_target(&current_policy[cpu], policy->max, 
-                             CPUFREQ_RELATION_H);
-               } else if (policy->min > cpu_set_freq[cpu]) {
-                       __cpufreq_driver_target(&current_policy[cpu], policy->min, 
-                             CPUFREQ_RELATION_L);
-               } else {
-                       __cpufreq_driver_target(&current_policy[cpu], cpu_set_freq[cpu],
-                             CPUFREQ_RELATION_L);
+                       __cpufreq_driver_target(policy, policy->max,
+                                               CPUFREQ_RELATION_H);
+               }
+               else if (policy->min > cpu_set_freq[cpu]) {
+                       __cpufreq_driver_target(policy, policy->min,
+                                               CPUFREQ_RELATION_L);
                }
-               memcpy (&current_policy[cpu], policy, sizeof(struct cpufreq_policy));
-               up(&userspace_sem);
+               else {
+                       __cpufreq_driver_target(policy, cpu_set_freq[cpu],
+                                               CPUFREQ_RELATION_L);
+               }
+               cpu_min_freq[cpu] = policy->min;
+               cpu_max_freq[cpu] = policy->max;
+               cpu_cur_freq[cpu] = policy->cur;
+               mutex_unlock(&userspace_mutex);
                break;
        }
        return 0;
index acda7d63d6feb9bf24d481f81243e6d991931133..501cc054cb3b150d8af4bd3c1c6d0196560ffb65 100644 (file)
@@ -956,6 +956,8 @@ static void ib_sa_remove_one(struct ib_device *device)
 
        ib_unregister_event_handler(&sa_dev->event_handler);
 
+       flush_scheduled_work();
+
        for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) {
                ib_unregister_mad_agent(sa_dev->port[i].agent);
                kref_put(&sa_dev->port[i].sm_ah->ref, free_sm_ah);
index 96ea79b63df7221747e1ccd65cf1622d93dc6885..903f85a4bc0cf4dfb461d6b9daf71a2a3e7d64d8 100644 (file)
@@ -902,6 +902,7 @@ static void __exit ib_uverbs_cleanup(void)
        unregister_filesystem(&uverbs_event_fs);
        class_destroy(uverbs_class);
        unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
+       flush_scheduled_work();
        idr_destroy(&ib_uverbs_pd_idr);
        idr_destroy(&ib_uverbs_mr_idr);
        idr_destroy(&ib_uverbs_mw_idr);
index a14eed08a0fcb5a4503ee59695671ae8e32ac82b..a19e0ed03d7c51eb4af6cf0960bc784696681fb7 100644 (file)
@@ -184,7 +184,7 @@ int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
                        ah->av->sl_tclass_flowlabel & cpu_to_be32(0xfffff);
                ib_get_cached_gid(&dev->ib_dev,
                                  be32_to_cpu(ah->av->port_pd) >> 24,
-                                 ah->av->gid_index,
+                                 ah->av->gid_index % dev->limits.gid_table_len,
                                  &header->grh.source_gid);
                memcpy(header->grh.destination_gid.raw,
                       ah->av->dgid, 16);
index fd3f5c862a5d92aef6b61202768bf9c29b24ccbe..c3b5f79d11681e2bd43cacad1bbdb73da88203a3 100644 (file)
@@ -505,7 +505,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
 
        list_add_tail(&neigh->list, &path->neigh_list);
 
-       if (path->pathrec.dlid) {
+       if (path->ah) {
                kref_get(&path->ah->ref);
                neigh->ah = path->ah;
 
@@ -591,7 +591,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
                return;
        }
 
-       if (path->pathrec.dlid) {
+       if (path->ah) {
                ipoib_dbg(priv, "Send unicast ARP to %04x\n",
                          be16_to_cpu(path->pathrec.dlid));
 
index 98039da0caf0e4ff67e958c3679540f4030b12a9..ccaa0c387076e8b0a36dc90dbb830528b09b93da 100644 (file)
@@ -97,6 +97,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_neigh *neigh, *tmp;
        unsigned long flags;
+       int tx_dropped = 0;
 
        ipoib_dbg_mcast(netdev_priv(dev),
                        "deleting multicast group " IPOIB_GID_FMT "\n",
@@ -123,8 +124,14 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
        if (mcast->ah)
                ipoib_put_ah(mcast->ah);
 
-       while (!skb_queue_empty(&mcast->pkt_queue))
+       while (!skb_queue_empty(&mcast->pkt_queue)) {
+               ++tx_dropped;
                dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
+       }
+
+       spin_lock_irqsave(&priv->tx_lock, flags);
+       priv->stats.tx_dropped += tx_dropped;
+       spin_unlock_irqrestore(&priv->tx_lock, flags);
 
        kfree(mcast);
 }
@@ -276,8 +283,10 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
        }
 
        /* actually send any queued packets */
+       spin_lock_irq(&priv->tx_lock);
        while (!skb_queue_empty(&mcast->pkt_queue)) {
                struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);
+               spin_unlock_irq(&priv->tx_lock);
 
                skb->dev = dev;
 
@@ -288,7 +297,9 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
 
                if (dev_queue_xmit(skb))
                        ipoib_warn(priv, "dev_queue_xmit failed to requeue packet\n");
+               spin_lock_irq(&priv->tx_lock);
        }
+       spin_unlock_irq(&priv->tx_lock);
 
        return 0;
 }
@@ -300,6 +311,7 @@ ipoib_mcast_sendonly_join_complete(int status,
 {
        struct ipoib_mcast *mcast = mcast_ptr;
        struct net_device *dev = mcast->dev;
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
 
        if (!status)
                ipoib_mcast_join_finish(mcast, mcmember);
@@ -310,8 +322,12 @@ ipoib_mcast_sendonly_join_complete(int status,
                                        IPOIB_GID_ARG(mcast->mcmember.mgid), status);
 
                /* Flush out any queued packets */
-               while (!skb_queue_empty(&mcast->pkt_queue))
+               spin_lock_irq(&priv->tx_lock);
+               while (!skb_queue_empty(&mcast->pkt_queue)) {
+                       ++priv->stats.tx_dropped;
                        dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
+               }
+               spin_unlock_irq(&priv->tx_lock);
 
                /* Clear the busy flag so we try again */
                clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
@@ -687,6 +703,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid,
                if (!mcast) {
                        ipoib_warn(priv, "unable to allocate memory for "
                                   "multicast structure\n");
+                       ++priv->stats.tx_dropped;
                        dev_kfree_skb_any(skb);
                        goto out;
                }
@@ -700,8 +717,10 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid,
        if (!mcast->ah) {
                if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE)
                        skb_queue_tail(&mcast->pkt_queue, skb);
-               else
+               else {
+                       ++priv->stats.tx_dropped;
                        dev_kfree_skb_any(skb);
+               }
 
                if (mcast->query)
                        ipoib_dbg_mcast(priv, "no address vector, "
index dd8c6a9ffc762a2bf8e071ced39cfa467b6920a9..b45a45ca7cc961c6152cb702cde8ae768b8b156e 100644 (file)
@@ -29,9 +29,6 @@
 #ifdef CONFIG_ARCH_OMAP
 #include <asm/arch/gpio.h>
 #endif
-
-#else
-#define        set_irq_type(irq,type)  do{}while(0)
 #endif
 
 
@@ -509,14 +506,14 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        ts->msg.complete = ads7846_rx;
        ts->msg.context = ts;
 
-       if (request_irq(spi->irq, ads7846_irq, SA_SAMPLE_RANDOM,
-                               spi->dev.bus_id, ts)) {
+       if (request_irq(spi->irq, ads7846_irq,
+                       SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
+                       spi->dev.bus_id, ts)) {
                dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
                input_unregister_device(&ts->input);
                kfree(ts);
                return -EBUSY;
        }
-       set_irq_type(spi->irq, IRQT_FALLING);
 
        dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
 
index 8a2e2657f4c28c0c304cbe1859861c3f2190d5f8..33ace373241cb4b80997b60bb52b29dc46c87f8b 100644 (file)
@@ -29,6 +29,8 @@
 #  For mptctl:
 #CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
 #
+#  For mptfc:
+#CFLAGS_mptfc.o += -DMPT_DEBUG_FC
 
 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
 
index d890b2b8a93e94973f345068f95b75e9121b679d..9a2c7605d49c930a45c10aaad9b3cc772dd2805e 100644 (file)
@@ -81,6 +81,10 @@ MODULE_LICENSE("GPL");
 /*
  *  cmd line parameters
  */
+static int mpt_msi_enable;
+module_param(mpt_msi_enable, int, 0);
+MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
+
 #ifdef MFCNT
 static int mfcounter = 0;
 #define PRINT_MF_COUNT 20000
@@ -174,7 +178,7 @@ static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
 static int     ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
 static void    mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
 static void    mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
-static void    mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);
+static void    mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void    mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
 
 /* module entry point */
@@ -313,7 +317,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
                if (ioc->bus_type == FC)
                        mpt_fc_log_info(ioc, log_info);
                else if (ioc->bus_type == SPI)
-                       mpt_sp_log_info(ioc, log_info);
+                       mpt_spi_log_info(ioc, log_info);
                else if (ioc->bus_type == SAS)
                        mpt_sas_log_info(ioc, log_info);
        }
@@ -1444,6 +1448,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ioc->pci_irq = -1;
        if (pdev->irq) {
+               if (mpt_msi_enable && !pci_enable_msi(pdev))
+                       printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", ioc->name);
+
                r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc);
 
                if (r < 0) {
@@ -1483,6 +1490,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 
                list_del(&ioc->list);
                free_irq(ioc->pci_irq, ioc);
+               if (mpt_msi_enable)
+                       pci_disable_msi(pdev);
+               if (ioc->alt_ioc)
+                       ioc->alt_ioc->alt_ioc = NULL;
                iounmap(mem);
                kfree(ioc);
                pci_set_drvdata(pdev, NULL);
@@ -2136,6 +2147,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
 
        if (ioc->pci_irq != -1) {
                free_irq(ioc->pci_irq, ioc);
+               if (mpt_msi_enable)
+                       pci_disable_msi(ioc->pcidev);
                ioc->pci_irq = -1;
        }
 
@@ -2157,6 +2170,10 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
        sz_last = ioc->alloc_total;
        dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
                        ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
+
+       if (ioc->alt_ioc)
+               ioc->alt_ioc->alt_ioc = NULL;
+
        kfree(ioc);
 }
 
@@ -2770,13 +2787,16 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
 
        /* RAID FW may take a long time to enable
         */
-       if ( (ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
-                       > MPI_FW_HEADER_PID_PROD_TARGET_SCSI ) {
-               rc = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
-                               reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag);
+       if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
+           > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
+           (ioc->bus_type == SAS)) {
+               rc = mpt_handshake_req_reply_wait(ioc, req_sz,
+               (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
+               300 /*seconds*/, sleepFlag);
        } else {
-               rc = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable,
-                               reply_sz, (u16*)&reply_buf, 30 /*seconds*/, sleepFlag);
+               rc = mpt_handshake_req_reply_wait(ioc, req_sz,
+               (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
+               30 /*seconds*/, sleepFlag);
        }
        return rc;
 }
@@ -4386,6 +4406,138 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
        return 0;
 }
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+static void
+mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
+    MpiEventDataRaid_t * pRaidEventData)
+{
+       int     volume;
+       int     reason;
+       int     disk;
+       int     status;
+       int     flags;
+       int     state;
+
+       volume  = pRaidEventData->VolumeID;
+       reason  = pRaidEventData->ReasonCode;
+       disk    = pRaidEventData->PhysDiskNum;
+       status  = le32_to_cpu(pRaidEventData->SettingsStatus);
+       flags   = (status >> 0) & 0xff;
+       state   = (status >> 8) & 0xff;
+
+       if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
+               return;
+       }
+
+       if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
+            reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
+           (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
+               printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
+                       ioc->name, disk);
+       } else {
+               printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
+                       ioc->name, volume);
+       }
+
+       switch(reason) {
+       case MPI_EVENT_RAID_RC_VOLUME_CREATED:
+               printk(MYIOC_s_INFO_FMT "  volume has been created\n",
+                       ioc->name);
+               break;
+
+       case MPI_EVENT_RAID_RC_VOLUME_DELETED:
+
+               printk(MYIOC_s_INFO_FMT "  volume has been deleted\n",
+                       ioc->name);
+               break;
+
+       case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
+               printk(MYIOC_s_INFO_FMT "  volume settings have been changed\n",
+                       ioc->name);
+               break;
+
+       case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
+               printk(MYIOC_s_INFO_FMT "  volume is now %s%s%s%s\n",
+                       ioc->name,
+                       state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
+                        ? "optimal"
+                        : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
+                         ? "degraded"
+                         : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
+                          ? "failed"
+                          : "state unknown",
+                       flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
+                        ? ", enabled" : "",
+                       flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
+                        ? ", quiesced" : "",
+                       flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
+                        ? ", resync in progress" : "" );
+               break;
+
+       case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
+               printk(MYIOC_s_INFO_FMT "  volume membership of PhysDisk %d has changed\n",
+                       ioc->name, disk);
+               break;
+
+       case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
+               printk(MYIOC_s_INFO_FMT "  PhysDisk has been created\n",
+                       ioc->name);
+               break;
+
+       case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
+               printk(MYIOC_s_INFO_FMT "  PhysDisk has been deleted\n",
+                       ioc->name);
+               break;
+
+       case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
+               printk(MYIOC_s_INFO_FMT "  PhysDisk settings have been changed\n",
+                       ioc->name);
+               break;
+
+       case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
+               printk(MYIOC_s_INFO_FMT "  PhysDisk is now %s%s%s\n",
+                       ioc->name,
+                       state == MPI_PHYSDISK0_STATUS_ONLINE
+                        ? "online"
+                        : state == MPI_PHYSDISK0_STATUS_MISSING
+                         ? "missing"
+                         : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
+                          ? "not compatible"
+                          : state == MPI_PHYSDISK0_STATUS_FAILED
+                           ? "failed"
+                           : state == MPI_PHYSDISK0_STATUS_INITIALIZING
+                            ? "initializing"
+                            : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
+                             ? "offline requested"
+                             : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
+                              ? "failed requested"
+                              : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
+                               ? "offline"
+                               : "state unknown",
+                       flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
+                        ? ", out of sync" : "",
+                       flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
+                        ? ", quiesced" : "" );
+               break;
+
+       case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
+               printk(MYIOC_s_INFO_FMT "  Domain Validation needed for PhysDisk %d\n",
+                       ioc->name, disk);
+               break;
+
+       case MPI_EVENT_RAID_RC_SMART_DATA:
+               printk(MYIOC_s_INFO_FMT "  SMART data received, ASC/ASCQ = %02xh/%02xh\n",
+                       ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
+               break;
+
+       case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
+               printk(MYIOC_s_INFO_FMT "  replacement of PhysDisk %d has started\n",
+                       ioc->name, disk);
+               break;
+       }
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     GetIoUnitPage2 - Retrieve BIOS version and boot order information.
@@ -4598,6 +4750,14 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
                                SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t  *) pbuf;
                                MpiDeviceInfo_t *pdevice = NULL;
 
+                               /*
+                                * Save "Set to Avoid SCSI Bus Resets" flag
+                                */
+                               ioc->spi_data.bus_reset =
+                                   (le32_to_cpu(pPP2->PortFlags) &
+                               MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
+                                   0 : 1 ;
+
                                /* Save the Port Page 2 data
                                 * (reformat into a 32bit quantity)
                                 */
@@ -5967,6 +6127,10 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
                        }
                }
                break;
+       case MPI_EVENT_INTEGRATED_RAID:
+               mptbase_raid_process_event_data(ioc,
+                   (MpiEventDataRaid_t *)pEventReply->Data);
+               break;
        default:
                break;
        }
@@ -6046,7 +6210,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *     mpt_sp_log_info - Log information returned from SCSI Parallel IOC.
+ *     mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @mr: Pointer to MPT reply frame
  *     @log_info: U32 LogInfo word from the IOC
@@ -6054,7 +6218,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
  *     Refer to lsi/sp_log.h.
  */
 static void
-mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
+mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
 {
        u32 info = log_info & 0x00FF0000;
        char *desc = "unknown";
index 47053ac65068566fa6675fa2a5ed08eb8199684e..ea2649ecad1fcccb9f19e33cc8bf1cce9276bd96 100644 (file)
@@ -76,8 +76,8 @@
 #define COPYRIGHT      "Copyright (c) 1999-2005 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "3.03.06"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.03.06"
+#define MPT_LINUX_VERSION_COMMON       "3.03.07"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.03.07"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
 #define  MPT_MAX_FRAME_SIZE            128
 #define  MPT_DEFAULT_FRAME_SIZE                128
 
-#define  MPT_REPLY_FRAME_SIZE          0x40  /* Must be a multiple of 8 */
+#define  MPT_REPLY_FRAME_SIZE          0x50  /* Must be a multiple of 8 */
 
 #define  MPT_SG_REQ_128_SCALE          1
 #define  MPT_SG_REQ_96_SCALE           2
@@ -510,9 +510,10 @@ struct mptfc_rport_info
 {
        struct list_head list;
        struct fc_rport *rport;
-       VirtDevice      *vdev;
+       struct scsi_target *starget;
        FCDevicePage0_t pg0;
        u8              flags;
+       u8              remap_needed;
 };
 
 /*
@@ -631,6 +632,7 @@ typedef struct _MPT_ADAPTER
        struct mutex             sas_topology_mutex;
        MPT_SAS_MGMT             sas_mgmt;
        int                      num_ports;
+       struct work_struct       mptscsih_persistTask;
 
        struct list_head         fc_rports;
        spinlock_t               fc_rport_lock; /* list and ri flags */
@@ -803,6 +805,12 @@ typedef struct _mpt_sge {
 #define dreplyprintk(x)
 #endif
 
+#ifdef DMPT_DEBUG_FC
+#define dfcprintk(x) printk x
+#else
+#define dfcprintk(x)
+#endif
+
 #ifdef MPT_DEBUG_TM
 #define dtmprintk(x) printk x
 #define DBG_DUMP_TM_REQUEST_FRAME(mfp) \
index b102c7666d0efcaf44f8a6e534ff340352b23489..c3a3499bce2ae8c3ece665ce11f98b6027a1cd83 100644 (file)
@@ -93,10 +93,11 @@ static int  mptfcDoneCtx = -1;
 static int     mptfcTaskCtx = -1;
 static int     mptfcInternalCtx = -1; /* Used only for internal commands */
 
-int mptfc_slave_alloc(struct scsi_device *device);
+static int mptfc_target_alloc(struct scsi_target *starget);
+static int mptfc_slave_alloc(struct scsi_device *sdev);
 static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
-    void (*done)(struct scsi_cmnd *));
-
+                     void (*done)(struct scsi_cmnd *));
+static void mptfc_target_destroy(struct scsi_target *starget);
 static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
 static void __devexit mptfc_remove(struct pci_dev *pdev);
 
@@ -107,10 +108,10 @@ static struct scsi_host_template mptfc_driver_template = {
        .name                           = "MPT FC Host",
        .info                           = mptscsih_info,
        .queuecommand                   = mptfc_qcmd,
-       .target_alloc                   = mptscsih_target_alloc,
+       .target_alloc                   = mptfc_target_alloc,
        .slave_alloc                    = mptfc_slave_alloc,
        .slave_configure                = mptscsih_slave_configure,
-       .target_destroy                 = mptscsih_target_destroy,
+       .target_destroy                 = mptfc_target_destroy,
        .slave_destroy                  = mptscsih_slave_destroy,
        .change_queue_depth             = mptscsih_change_queue_depth,
        .eh_abort_handler               = mptscsih_abort,
@@ -347,15 +348,34 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
        return 0;
 }
 
+static void
+mptfc_remap_sdev(struct scsi_device *sdev, void *arg)
+{
+       VirtDevice              *vdev;
+       VirtTarget              *vtarget;
+       struct scsi_target      *starget;
+
+       starget = scsi_target(sdev);
+       if (starget->hostdata == arg) {
+               vtarget = arg;
+               vdev = sdev->hostdata;
+               if (vdev) {
+                       vdev->bus_id = vtarget->bus_id;
+                       vdev->target_id = vtarget->target_id;
+               }
+       }
+}
+
 static void
 mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
 {
        struct fc_rport_identifiers rport_ids;
        struct fc_rport         *rport;
        struct mptfc_rport_info *ri;
-       int                     match = 0;
-       u64                     port_name;
+       int                     new_ri = 1;
+       u64                     pn;
        unsigned long           flags;
+       VirtTarget              *vtarget;
 
        if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
                return;
@@ -363,14 +383,14 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
        /* scan list looking for a match */
        spin_lock_irqsave(&ioc->fc_rport_lock, flags);
        list_for_each_entry(ri, &ioc->fc_rports, list) {
-               port_name = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
-               if (port_name == rport_ids.port_name) { /* match */
+               pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+               if (pn == rport_ids.port_name) {        /* match */
                        list_move_tail(&ri->list, &ioc->fc_rports);
-                       match = 1;
+                       new_ri = 0;
                        break;
                }
        }
-       if (!match) {   /* allocate one */
+       if (new_ri) {   /* allocate one */
                spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
                ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
                if (!ri)
@@ -382,40 +402,43 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
        ri->pg0 = *pg0; /* add/update pg0 data */
        ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
 
+       /* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
        if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
                ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
                spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
-               rport = fc_remote_port_add(ioc->sh,channel, &rport_ids);
+               rport = fc_remote_port_add(ioc->sh, channel, &rport_ids);
                spin_lock_irqsave(&ioc->fc_rport_lock, flags);
                if (rport) {
-                       if (*((struct mptfc_rport_info **)rport->dd_data) != ri) {
-                               ri->flags &= ~MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
-                               ri->vdev = NULL;
-                               ri->rport = rport;
-                               *((struct mptfc_rport_info **)rport->dd_data) = ri;
-                       }
-                       rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+                       ri->rport = rport;
+                       if (new_ri) /* may have been reset by user */
+                               rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+                       *((struct mptfc_rport_info **)rport->dd_data) = ri;
                        /*
                         * if already mapped, remap here.  If not mapped,
-                        * slave_alloc will allocate vdev and map
+                        * target_alloc will allocate vtarget and map,
+                        * slave_alloc will fill in vdev from vtarget.
                         */
-                       if (ri->flags & MPT_RPORT_INFO_FLAGS_MAPPED_VDEV) {
-                               ri->vdev->target_id = ri->pg0.CurrentTargetID;
-                               ri->vdev->bus_id = ri->pg0.CurrentBus;
-                               ri->vdev->vtarget->target_id = ri->vdev->target_id;
-                               ri->vdev->vtarget->bus_id = ri->vdev->bus_id;
+                       if (ri->starget) {
+                               vtarget = ri->starget->hostdata;
+                               if (vtarget) {
+                                       vtarget->target_id = pg0->CurrentTargetID;
+                                       vtarget->bus_id = pg0->CurrentBus;
+                                       starget_for_each_device(ri->starget,
+                                               vtarget,mptfc_remap_sdev);
+                               }
+                               ri->remap_needed = 0;
                        }
-                       #ifdef MPT_DEBUG
-                       printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
+                       dfcprintk ((MYIOC_s_INFO_FMT
+                               "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
                                "rport tid %d, tmo %d\n",
-                                       ioc->sh->host_no,
+                                       ioc->name,
+                                       oc->sh->host_no,
                                        pg0->PortIdentifier,
                                        pg0->WWNN,
                                        pg0->WWPN,
                                        pg0->CurrentTargetID,
                                        ri->rport->scsi_target_id,
-                                       ri->rport->dev_loss_tmo);
-                       #endif
+                                       ri->rport->dev_loss_tmo));
                } else {
                        list_del(&ri->list);
                        kfree(ri);
@@ -426,6 +449,65 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
 
 }
 
+/*
+ *     OS entry point to allow for host driver to free allocated memory
+ *     Called if no device present or device being unloaded
+ */
+static void
+mptfc_target_destroy(struct scsi_target *starget)
+{
+       struct fc_rport         *rport;
+       struct mptfc_rport_info *ri;
+
+       rport = starget_to_rport(starget);
+       if (rport) {
+               ri = *((struct mptfc_rport_info **)rport->dd_data);
+               if (ri) /* better be! */
+                       ri->starget = NULL;
+       }
+       if (starget->hostdata)
+               kfree(starget->hostdata);
+       starget->hostdata = NULL;
+}
+
+/*
+ *     OS entry point to allow host driver to alloc memory
+ *     for each scsi target. Called once per device the bus scan.
+ *     Return non-zero if allocation fails.
+ */
+static int
+mptfc_target_alloc(struct scsi_target *starget)
+{
+       VirtTarget              *vtarget;
+       struct fc_rport         *rport;
+       struct mptfc_rport_info *ri;
+       int                     rc;
+
+       vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
+       if (!vtarget)
+               return -ENOMEM;
+       starget->hostdata = vtarget;
+
+       rc = -ENODEV;
+       rport = starget_to_rport(starget);
+       if (rport) {
+               ri = *((struct mptfc_rport_info **)rport->dd_data);
+               if (ri) {       /* better be! */
+                       vtarget->target_id = ri->pg0.CurrentTargetID;
+                       vtarget->bus_id = ri->pg0.CurrentBus;
+                       ri->starget = starget;
+                       ri->remap_needed = 0;
+                       rc = 0;
+               }
+       }
+       if (rc != 0) {
+               kfree(vtarget);
+               starget->hostdata = NULL;
+       }
+
+       return rc;
+}
+
 /*
  *     OS entry point to allow host driver to alloc memory
  *     for each scsi device. Called once per device the bus scan.
@@ -440,7 +522,6 @@ mptfc_slave_alloc(struct scsi_device *sdev)
        VirtDevice              *vdev;
        struct scsi_target      *starget;
        struct fc_rport         *rport;
-       struct mptfc_rport_info *ri;
        unsigned long           flags;
 
 
@@ -451,55 +532,44 @@ mptfc_slave_alloc(struct scsi_device *sdev)
 
        hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
 
-       vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
+       vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
        if (!vdev) {
                printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
                                hd->ioc->name, sizeof(VirtDevice));
                return -ENOMEM;
        }
-       memset(vdev, 0, sizeof(VirtDevice));
 
        spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);
 
-       if (!(ri = *((struct mptfc_rport_info **)rport->dd_data))) {
-               spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
-               kfree(vdev);
-               return -ENODEV;
-       }
-
        sdev->hostdata = vdev;
        starget = scsi_target(sdev);
        vtarget = starget->hostdata;
+
        if (vtarget->num_luns == 0) {
+               vtarget->ioc_id = hd->ioc->id;
                vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
                                  MPT_TARGET_FLAGS_VALID_INQUIRY;
                hd->Targets[sdev->id] = vtarget;
        }
 
-       vtarget->target_id = vdev->target_id;
-       vtarget->bus_id = vdev->bus_id;
-
        vdev->vtarget = vtarget;
        vdev->ioc_id = hd->ioc->id;
        vdev->lun = sdev->lun;
-       vdev->target_id = ri->pg0.CurrentTargetID;
-       vdev->bus_id = ri->pg0.CurrentBus;
-
-       ri->flags |= MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
-       ri->vdev = vdev;
+       vdev->target_id = vtarget->target_id;
+       vdev->bus_id = vtarget->bus_id;
 
        spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
 
        vtarget->num_luns++;
 
-#ifdef MPT_DEBUG
-       printk ("mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
+       dfcprintk ((MYIOC_s_INFO_FMT
+               "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
                "CurrentTargetID %d, %x %llx %llx\n",
-                       sdev->host->host_no,
-                       vtarget->num_luns,
-                       sdev->id, ri->pg0.CurrentTargetID,
-                       ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN);
-#endif
+               ioc->name,
+               sdev->host->host_no,
+               vtarget->num_luns,
+               sdev->id, ri->pg0.CurrentTargetID,
+               ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN));
 
        return 0;
 }
@@ -507,6 +577,7 @@ mptfc_slave_alloc(struct scsi_device *sdev)
 static int
 mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
+       struct mptfc_rport_info *ri;
        struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
        int             err;
 
@@ -516,6 +587,10 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
                done(SCpnt);
                return 0;
        }
+       ri = *((struct mptfc_rport_info **)rport->dd_data);
+       if (unlikely(ri->remap_needed))
+               return SCSI_MLQUEUE_HOST_BUSY;
+
        return mptscsih_qcmd(SCpnt,done);
 }
 
@@ -591,16 +666,20 @@ mptfc_rescan_devices(void *arg)
 
                                ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
                                               MPT_RPORT_INFO_FLAGS_MISSING);
+                               ri->remap_needed = 1;
                                fc_remote_port_delete(ri->rport);
                                /*
                                 * remote port not really deleted 'cause
                                 * binding is by WWPN and driver only
-                                * registers FCP_TARGETs
+                                * registers FCP_TARGETs but cannot trust
+                                * data structures.
                                 */
-                               #ifdef MPT_DEBUG
-                               printk ("mptfc_rescan.%d: %llx deleted\n",
-                                       ioc->sh->host_no, ri->pg0.WWPN);
-                               #endif
+                               ri->rport = NULL;
+                               dfcprintk ((MYIOC_s_INFO_FMT
+                                       "mptfc_rescan.%d: %llx deleted\n",
+                                       ioc->name,
+                                       ioc->sh->host_no,
+                                       ri->pg0.WWPN));
                        }
                }
                spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
@@ -872,9 +951,8 @@ mptfc_init(void)
        }
 
        error = pci_register_driver(&mptfc_driver);
-       if (error) {
+       if (error)
                fc_release_transport(mptfc_transport_template);
-       }
 
        return error;
 }
@@ -885,7 +963,8 @@ mptfc_init(void)
  *     @pdev: Pointer to pci_dev structure
  *
  */
-static void __devexit mptfc_remove(struct pci_dev *pdev)
+static void __devexit
+mptfc_remove(struct pci_dev *pdev)
 {
        MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
        struct mptfc_rport_info *p, *n;
index 5a06d8d8694eb3cff0322e479a089ffb5d7021c1..2512d0e6155ede3b55f1996b13fe69b6b78eda0a 100644 (file)
@@ -89,6 +89,8 @@ static int    mptsasMgmtCtx = -1;
 enum mptsas_hotplug_action {
        MPTSAS_ADD_DEVICE,
        MPTSAS_DEL_DEVICE,
+       MPTSAS_ADD_RAID,
+       MPTSAS_DEL_RAID,
 };
 
 struct mptsas_hotplug_event {
@@ -114,6 +116,7 @@ struct mptsas_hotplug_event {
 
 struct mptsas_devinfo {
        u16     handle;         /* unique id to address this device */
+       u16     handle_parent;  /* unique id to address parent device */
        u8      phy_id;         /* phy number of parent device */
        u8      port_id;        /* sas physical port this device
                                   is assoc'd with */
@@ -301,9 +304,8 @@ mptsas_slave_alloc(struct scsi_device *sdev)
        }
        mutex_unlock(&hd->ioc->sas_topology_mutex);
 
-       printk("No matching SAS device found!!\n");
        kfree(vdev);
-       return -ENODEV;
+       return -ENXIO;
 
  out:
        vtarget->ioc_id = vdev->ioc_id;
@@ -321,6 +323,7 @@ mptsas_slave_destroy(struct scsi_device *sdev)
        struct sas_rphy *rphy;
        struct mptsas_portinfo *p;
        int i;
+       VirtDevice *vdev;
 
        /*
         * Handle hotplug removal case.
@@ -344,8 +347,29 @@ mptsas_slave_destroy(struct scsi_device *sdev)
  out:
        mutex_unlock(&hd->ioc->sas_topology_mutex);
        /*
-        * TODO: Issue target reset to flush firmware outstanding commands.
+        * Issue target reset to flush firmware outstanding commands.
         */
+       vdev = sdev->hostdata;
+       if (vdev->configured_lun){
+               if (mptscsih_TMHandler(hd,
+                    MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+                    vdev->bus_id,
+                    vdev->target_id,
+                    0, 0, 5 /* 5 second timeout */)
+                    < 0){
+
+                       /* The TM request failed!
+                        * Fatal error case.
+                        */
+                       printk(MYIOC_s_WARN_FMT
+                      "Error processing TaskMgmt id=%d TARGET_RESET\n",
+                               hd->ioc->name,
+                               vdev->target_id);
+
+                       hd->tmPending = 0;
+                       hd->tmState = TM_STATE_NONE;
+               }
+       }
        mptscsih_slave_destroy(sdev);
 }
 
@@ -714,6 +738,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
        mptsas_print_device_pg0(buffer);
 
        device_info->handle = le16_to_cpu(buffer->DevHandle);
+       device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
        device_info->phy_id = buffer->PhyNum;
        device_info->port_id = buffer->PhysicalPort;
        device_info->id = buffer->TargetID;
@@ -863,6 +888,26 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
        return error;
 }
 
+/*
+ * Returns true if there is a scsi end device
+ */
+static inline int
+mptsas_is_end_device(struct mptsas_devinfo * attached)
+{
+       if ((attached->handle) &&
+           (attached->device_info &
+           MPI_SAS_DEVICE_INFO_END_DEVICE) &&
+           ((attached->device_info &
+           MPI_SAS_DEVICE_INFO_SSP_TARGET) |
+           (attached->device_info &
+           MPI_SAS_DEVICE_INFO_STP_TARGET) |
+           (attached->device_info &
+           MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
+               return 1;
+       else
+               return 0;
+}
+
 static void
 mptsas_parse_device_info(struct sas_identify *identify,
                struct mptsas_devinfo *device_info)
@@ -1227,7 +1272,7 @@ mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
 }
 
 static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
+mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
 {
        struct mptsas_portinfo *port_info;
        struct mptsas_phyinfo *phy_info = NULL;
@@ -1239,12 +1284,12 @@ mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
         */
        mutex_lock(&ioc->sas_topology_mutex);
        list_for_each_entry(port_info, &ioc->sas_topology, list) {
-               for (i = 0; i < port_info->num_phys; i++) {
-                       if (port_info->phy_info[i].attached.handle == handle) {
-                               phy_info = &port_info->phy_info[i];
-                               break;
-                       }
-               }
+               for (i = 0; i < port_info->num_phys; i++)
+                       if (mptsas_is_end_device(&port_info->phy_info[i].attached))
+                               if (port_info->phy_info[i].attached.id == id) {
+                                       phy_info = &port_info->phy_info[i];
+                                       break;
+                               }
        }
        mutex_unlock(&ioc->sas_topology_mutex);
 
@@ -1258,36 +1303,58 @@ mptsas_hotplug_work(void *arg)
        MPT_ADAPTER *ioc = ev->ioc;
        struct mptsas_phyinfo *phy_info;
        struct sas_rphy *rphy;
+       struct scsi_device *sdev;
        char *ds = NULL;
-
-       if (ev->device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
-               ds = "ssp";
-       if (ev->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
-               ds = "stp";
-       if (ev->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
-               ds = "sata";
+       struct mptsas_devinfo sas_device;
 
        switch (ev->event_type) {
        case MPTSAS_DEL_DEVICE:
-               printk(MYIOC_s_INFO_FMT
-                      "removing %s device, channel %d, id %d, phy %d\n",
-                      ioc->name, ds, ev->channel, ev->id, ev->phy_id);
 
-               phy_info = mptsas_find_phyinfo_by_handle(ioc, ev->handle);
+               phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id);
                if (!phy_info) {
                        printk("mptsas: remove event for non-existant PHY.\n");
                        break;
                }
 
+               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+                       ds = "ssp";
+               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
+                       ds = "stp";
+               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+                       ds = "sata";
+
+               printk(MYIOC_s_INFO_FMT
+                      "removing %s device, channel %d, id %d, phy %d\n",
+                      ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
+
                if (phy_info->rphy) {
                        sas_rphy_delete(phy_info->rphy);
                        phy_info->rphy = NULL;
                }
                break;
        case MPTSAS_ADD_DEVICE:
-               printk(MYIOC_s_INFO_FMT
-                      "attaching %s device, channel %d, id %d, phy %d\n",
-                      ioc->name, ds, ev->channel, ev->id, ev->phy_id);
+
+               /*
+                * When there is no sas address,
+                * RAID volumes are being deleted,
+                * and hidden phy disk are being added.
+                * We don't know the SAS data yet,
+                * so lookup sas device page to get
+                * pertaining info
+                */
+               if (!ev->sas_address) {
+                       if (mptsas_sas_device_pg0(ioc,
+                           &sas_device, ev->id,
+                           (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+                            MPI_SAS_DEVICE_PGAD_FORM_SHIFT)))
+                               break;
+                       ev->handle = sas_device.handle;
+                       ev->parent_handle = sas_device.handle_parent;
+                       ev->channel = sas_device.channel;
+                       ev->phy_id = sas_device.phy_id;
+                       ev->sas_address = sas_device.sas_address;
+                       ev->device_info = sas_device.device_info;
+               }
 
                phy_info = mptsas_find_phyinfo_by_parent(ioc,
                                ev->parent_handle, ev->phy_id);
@@ -1310,10 +1377,23 @@ mptsas_hotplug_work(void *arg)
                phy_info->attached.sas_address = ev->sas_address;
                phy_info->attached.device_info = ev->device_info;
 
+               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+                       ds = "ssp";
+               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
+                       ds = "stp";
+               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+                       ds = "sata";
+
+               printk(MYIOC_s_INFO_FMT
+                      "attaching %s device, channel %d, id %d, phy %d\n",
+                      ioc->name, ds, ev->channel, ev->id, ev->phy_id);
+
+
                rphy = sas_rphy_alloc(phy_info->phy);
                if (!rphy)
                        break; /* non-fatal: an rphy can be added later */
 
+               rphy->scsi_target_id = phy_info->attached.id;
                mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
                if (sas_rphy_add(rphy)) {
                        sas_rphy_free(rphy);
@@ -1322,6 +1402,40 @@ mptsas_hotplug_work(void *arg)
 
                phy_info->rphy = rphy;
                break;
+       case MPTSAS_ADD_RAID:
+               sdev = scsi_device_lookup(
+                       ioc->sh,
+                       ioc->num_ports,
+                       ev->id,
+                       0);
+               if (sdev) {
+                       scsi_device_put(sdev);
+                       break;
+               }
+               printk(MYIOC_s_INFO_FMT
+                      "attaching device, channel %d, id %d\n",
+                      ioc->name, ioc->num_ports, ev->id);
+               scsi_add_device(ioc->sh,
+                       ioc->num_ports,
+                       ev->id,
+                       0);
+               mpt_findImVolumes(ioc);
+               break;
+       case MPTSAS_DEL_RAID:
+               sdev = scsi_device_lookup(
+                       ioc->sh,
+                       ioc->num_ports,
+                       ev->id,
+                       0);
+               if (!sdev)
+                       break;
+               printk(MYIOC_s_INFO_FMT
+                      "removing device, channel %d, id %d\n",
+                      ioc->name, ioc->num_ports, ev->id);
+               scsi_remove_device(sdev);
+               scsi_device_put(sdev);
+               mpt_findImVolumes(ioc);
+               break;
        }
 
        kfree(ev);
@@ -1372,23 +1486,94 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc,
        schedule_work(&ev->work);
 }
 
+static void
+mptscsih_send_raid_event(MPT_ADAPTER *ioc,
+               EVENT_DATA_RAID *raid_event_data)
+{
+       struct mptsas_hotplug_event *ev;
+       RAID_VOL0_STATUS * volumeStatus;
+
+       if (ioc->bus_type != SAS)
+               return;
+
+       ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+       if (!ev) {
+               printk(KERN_WARNING "mptsas: lost hotplug event\n");
+               return;
+       }
+
+       memset(ev,0,sizeof(struct mptsas_hotplug_event));
+       INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
+       ev->ioc = ioc;
+       ev->id = raid_event_data->VolumeID;
+
+       switch (raid_event_data->ReasonCode) {
+       case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
+               ev->event_type = MPTSAS_ADD_DEVICE;
+               break;
+       case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
+               ev->event_type = MPTSAS_DEL_DEVICE;
+               break;
+       case MPI_EVENT_RAID_RC_VOLUME_DELETED:
+               ev->event_type = MPTSAS_DEL_RAID;
+               break;
+       case MPI_EVENT_RAID_RC_VOLUME_CREATED:
+               ev->event_type = MPTSAS_ADD_RAID;
+               break;
+       case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
+               volumeStatus = (RAID_VOL0_STATUS *) &
+                   raid_event_data->SettingsStatus;
+               ev->event_type = (volumeStatus->State ==
+                   MPI_RAIDVOL0_STATUS_STATE_FAILED) ?
+                   MPTSAS_DEL_RAID : MPTSAS_ADD_RAID;
+               break;
+       default:
+               break;
+       }
+       schedule_work(&ev->work);
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* work queue thread to clear the persitency table */
+static void
+mptscsih_sas_persist_clear_table(void * arg)
+{
+       MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
+
+       mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
+}
+
 static int
 mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
 {
+       int rc=1;
        u8 event = le32_to_cpu(reply->Event) & 0xFF;
 
        if (!ioc->sh)
-               return 1;
+               goto out;
 
        switch (event) {
        case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
                mptscsih_send_sas_event(ioc,
                        (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
-               return 1;               /* currently means nothing really */
-
+               break;
+       case MPI_EVENT_INTEGRATED_RAID:
+               mptscsih_send_raid_event(ioc,
+                       (EVENT_DATA_RAID *)reply->Data);
+               break;
+       case MPI_EVENT_PERSISTENT_TABLE_FULL:
+               INIT_WORK(&ioc->mptscsih_persistTask,
+                   mptscsih_sas_persist_clear_table,
+                   (void *)ioc);
+               schedule_work(&ioc->mptscsih_persistTask);
+               break;
        default:
-               return mptscsih_event_process(ioc, reply);
+               rc = mptscsih_event_process(ioc, reply);
+               break;
        }
+ out:
+
+       return rc;
 }
 
 static int
index cdac5578fdf220caefb48a3356710393558372ff..05789e50546491df632331c58b6b5ff3e867f4fa 100644 (file)
@@ -144,7 +144,6 @@ static int  mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
 static int     mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
 static u32     SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
 
-static int     mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
 static int     mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
 
 int            mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
@@ -159,11 +158,9 @@ static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
 int            mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static int     mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
 static void    mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
-static void    mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget);
+static void    mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
 static int     mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
 
-static struct work_struct   mptscsih_persistTask;
-
 #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
 static int     mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
 static void    mptscsih_domainValidation(void *hd);
@@ -563,11 +560,24 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
        MPT_SCSI_HOST   *hd;
        SCSIIORequest_t *pScsiReq;
        SCSIIOReply_t   *pScsiReply;
-       u16              req_idx;
+       u16              req_idx, req_idx_MR;
 
        hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
 
        req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+       req_idx_MR = (mr != NULL) ?
+           le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
+       if ((req_idx != req_idx_MR) ||
+           (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) {
+               printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n",
+                   ioc->name);
+               printk (MYIOC_s_ERR_FMT
+                   "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
+                   ioc->name, req_idx, req_idx_MR, mf, mr,
+                   hd->ScsiLookup[req_idx_MR]);
+               return 0;
+       }
+
        sc = hd->ScsiLookup[req_idx];
        if (sc == NULL) {
                MPIHeader_t *hdr = (MPIHeader_t *)mf;
@@ -730,6 +740,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 
                        break;
 
+               case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:           /* 0x0044 */
+                       sc->resid=0;
                case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:        /* 0x0040 */
                case MPI_IOCSTATUS_SUCCESS:                     /* 0x0000 */
                        if (scsi_status == MPI_SCSI_STATUS_BUSY)
@@ -789,7 +801,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:      /* 0x0006 */
                case MPI_IOCSTATUS_INVALID_FIELD:               /* 0x0007 */
                case MPI_IOCSTATUS_INVALID_STATE:               /* 0x0008 */
-               case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:           /* 0x0044 */
                case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:          /* 0x0046 */
                case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:       /* 0x004A */
                default:
@@ -1530,7 +1541,7 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
  *
  *     Returns 0 for SUCCESS or -1 if FAILED.
  */
-static int
+int
 mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
 {
        MPT_ADAPTER     *ioc;
@@ -1721,6 +1732,20 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun
        return retval;
 }
 
+static int
+mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
+{
+       switch (ioc->bus_type) {
+       case FC:
+               return 40;
+       case SAS:
+               return 10;
+       case SPI:
+       default:
+               return 2;
+       }
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
@@ -1792,7 +1817,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
        vdev = SCpnt->device->hostdata;
        retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
                vdev->bus_id, vdev->target_id, vdev->lun,
-               ctx2abort, 2 /* 2 second timeout */);
+               ctx2abort, mptscsih_get_tm_timeout(ioc));
 
        printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
                hd->ioc->name,
@@ -1843,7 +1868,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
        vdev = SCpnt->device->hostdata;
        retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
                vdev->bus_id, vdev->target_id,
-               0, 0, 5 /* 5 second timeout */);
+               0, 0, mptscsih_get_tm_timeout(hd->ioc));
 
        printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
                hd->ioc->name,
@@ -1893,7 +1918,7 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
 
        vdev = SCpnt->device->hostdata;
        retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-               vdev->bus_id, 0, 0, 0, 5 /* 5 second timeout */);
+               vdev->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
 
        printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
                hd->ioc->name,
@@ -2015,6 +2040,42 @@ mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
        return status;
 }
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static void
+mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
+{
+       char *desc;
+
+       switch (response_code) {
+       case MPI_SCSITASKMGMT_RSP_TM_COMPLETE:
+               desc = "The task completed.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_INVALID_FRAME:
+               desc = "The IOC received an invalid frame status.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
+               desc = "The task type is not supported.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_TM_FAILED:
+               desc = "The requested task failed.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED:
+               desc = "The task completed successfully.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN:
+               desc = "The LUN request is invalid.";
+               break;
+       case MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
+               desc = "The task is in the IOC queue and has not been sent to target.";
+               break;
+       default:
+               desc = "unknown";
+               break;
+       }
+       printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n",
+               ioc->name, response_code, desc);
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mptscsih_taskmgmt_complete - Registered with Fusion MPT base driver
@@ -2064,6 +2125,11 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
                /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
                tmType = pScsiTmReq->TaskType;
 
+               if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
+                   pScsiTmReply->ResponseCode)
+                       mptscsih_taskmgmt_response_code(ioc,
+                           pScsiTmReply->ResponseCode);
+
                dtmprintk((MYIOC_s_WARN_FMT "  TaskType = %d, TerminationCount=%d\n",
                                ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
                DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
@@ -2255,7 +2321,7 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
        vtarget->luns[0] &= ~(1 << vdevice->lun);
        vtarget->num_luns--;
        if (vtarget->num_luns == 0) {
-               mptscsih_negotiate_to_asyn_narrow(hd, vtarget);
+               mptscsih_negotiate_to_asyn_narrow(hd, vdevice);
                if (hd->ioc->bus_type == SPI) {
                        if (mptscsih_is_phys_disk(hd->ioc, vtarget->target_id)) {
                                hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
@@ -2584,16 +2650,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
        return 1;               /* currently means nothing really */
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* work queue thread to clear the persitency table */
-static void
-mptscsih_sas_persist_clear_table(void * arg)
-{
-       MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
-
-       mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
-}
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 int
 mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
@@ -2656,13 +2712,6 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
                break;
        }
 
-       /* Persistent table is full. */
-       case MPI_EVENT_PERSISTENT_TABLE_FULL:
-               INIT_WORK(&mptscsih_persistTask,
-                   mptscsih_sas_persist_clear_table,(void *)ioc);
-               schedule_work(&mptscsih_persistTask);
-               break;
-
        case MPI_EVENT_NONE:                            /* 00 */
        case MPI_EVENT_LOG_DATA:                        /* 01 */
        case MPI_EVENT_STATE_CHANGE:                    /* 02 */
@@ -3863,8 +3912,9 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
  *
  */
 static void
-mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget)
+mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
 {
+       VirtTarget              *vtarget = vdevice->vtarget;
        MPT_ADAPTER             *ioc= hd->ioc;
        SCSIDevicePage1_t       *pcfg1Data;
        CONFIGPARMS              cfg;
@@ -3874,7 +3924,8 @@ mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget)
        int                      requested, configuration, data,i;
        u8                       flags, factor;
 
-       if (ioc->bus_type != SPI)
+       if ((ioc->bus_type != SPI) ||
+               (!vdevice->configured_lun))
                return;
 
        if (!ioc->spi_data.sdp1length)
@@ -3910,7 +3961,7 @@ mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget)
                        }
                        mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
                                &configuration, flags);
-                       dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
+                       dnegoprintk(("nego asyn narrow: id=%d width=0 factor=MPT_ASYNC "
                                "offset=0 negoFlags=%x request=%x config=%x\n",
                                id, flags, requested, configuration));
                        pcfg1Data->RequestedParameters = cpu_to_le32(requested);
@@ -3923,7 +3974,7 @@ mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget)
                flags = vtarget->negoFlags;
                mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
                                &configuration, flags);
-               dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC "
+               dnegoprintk(("nego asyn narrow: id=%d width=0 factor=MPT_ASYNC "
                        "offset=0 negoFlags=%x request=%x config=%x\n",
                        vtarget->target_id, flags, requested, configuration));
                pcfg1Data->RequestedParameters = cpu_to_le32(requested);
@@ -5620,5 +5671,6 @@ EXPORT_SYMBOL(mptscsih_event_process);
 EXPORT_SYMBOL(mptscsih_ioc_reset);
 EXPORT_SYMBOL(mptscsih_change_queue_depth);
 EXPORT_SYMBOL(mptscsih_timer_expired);
+EXPORT_SYMBOL(mptscsih_TMHandler);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
index d3cba12f4bd95c38c110327bfbde76d9d6ecf1af..44b248d51ea3174ff33d34024ac50b43e6bec672 100644 (file)
@@ -108,3 +108,4 @@ extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pE
 extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
 extern void mptscsih_timer_expired(unsigned long data);
+extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
index 7dce29277cb748e51e1ef8a3956f618cddc28818..f148dfa39117edb097bb5f481dcb9c8bad05bd60 100644 (file)
@@ -384,6 +384,14 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_mptspi_probe;
        }
 
+       /*
+        * issue internal bus reset
+        */
+       if (ioc->spi_data.bus_reset)
+               mptscsih_TMHandler(hd,
+                   MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+                   0, 0, 0, 0, 5);
+
        scsi_scan_host(sh);
        return 0;
 
@@ -445,7 +453,7 @@ static void __exit
 mptspi_exit(void)
 {
        pci_unregister_driver(&mptspi_driver);
-       
+
        mpt_reset_deregister(mptspiDoneCtx);
        dprintk((KERN_INFO MYNAM
          ": Deregistered for IOC reset notifications\n"));
index 7e98434cfa37783b1cfa45c1bd162e9a56f14bad..9783caf49696a8cf4cf74a77d907758c59ba846f 100644 (file)
@@ -50,7 +50,7 @@ void ibmasm_register_uart(struct service_processor *sp)
        memset(&uport, 0, sizeof(struct uart_port));
        uport.irq       = sp->irq;
        uport.uartclk   = 3686400;
-       uport.flags     = UPF_AUTOPROBE | UPF_SHARE_IRQ;
+       uport.flags     = UPF_SHARE_IRQ;
        uport.iotype    = UPIO_MEM;
        uport.membase   = iomem_base;
 
index 626508afe1b176ce9dd1d2b0fcdab52f766dc1bc..6a6a08441804b0bd1d902f6e2d691976d5471e9b 100644 (file)
@@ -2034,13 +2034,28 @@ config SKGE
          It does not support the link failover and network management 
          features that "portable" vendor supplied sk98lin driver does.
 
+         This driver supports adapters based on the original Yukon chipset:
+         Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T,
+         Linksys EG1032/EG1064, 3Com 3C940/3C940B, SysKonnect SK-9871/9872.
+
+         It does not support the newer Yukon2 chipset: a separate driver,
+         sky2, is provided for Yukon2-based adapters.
+
+         To compile this driver as a module, choose M here: the module
+         will be called skge.  This is recommended.
 
 config SKY2
        tristate "SysKonnect Yukon2 support (EXPERIMENTAL)"
        depends on PCI && EXPERIMENTAL
        select CRC32
        ---help---
-         This driver support the Marvell Yukon 2 Gigabit Ethernet adapter.
+         This driver supports Gigabit Ethernet adapters based on the the
+         Marvell Yukon 2 chipset:
+         Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/
+         88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21
+
+         This driver does not support the original Yukon chipset: a seperate
+         driver, skge, is provided for Yukon-based adapters.
 
          To compile this driver as a module, choose M here: the module
          will be called sky2.  This is recommended.
@@ -2050,8 +2065,15 @@ config SK98LIN
        depends on PCI
        ---help---
          Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx
-         compliant Gigabit Ethernet Adapter. The following adapters are supported
-         by this driver:
+         compliant Gigabit Ethernet Adapter.
+
+         This driver supports the original Yukon chipset. A cleaner driver is 
+         also available (skge) which seems to work better than this one.
+
+         This driver does not support the newer Yukon2 chipset. A seperate
+         driver, sky2, is provided to support Yukon2-based adapters.
+
+         The following adapters are supported by this driver:
            - 3Com 3C940 Gigabit LOM Ethernet Adapter
            - 3Com 3C941 Gigabit LOM Ethernet Adapter
            - Allied Telesyn AT-2970LX Gigabit Ethernet Adapter
index b8953de5664a4cdf091374af819525518414a6cd..b508812e97acc2bb0d632b0a49bb5f120a0439a6 100644 (file)
@@ -1002,6 +1002,8 @@ static int __devinit ace_init(struct net_device *dev)
 
        mac1 = 0;
        for(i = 0; i < 4; i++) {
+               int tmp;
+
                mac1 = mac1 << 8;
                tmp = read_eeprom_byte(dev, 0x8c+i);
                if (tmp < 0) {
@@ -1012,6 +1014,8 @@ static int __devinit ace_init(struct net_device *dev)
        }
        mac2 = 0;
        for(i = 4; i < 8; i++) {
+               int tmp;
+
                mac2 = mac2 << 8;
                tmp = read_eeprom_byte(dev, 0x8c+i);
                if (tmp < 0) {
index df9d6e80c4f29f88fb8f96a542cdbe89c5e08021..c3267e4e1bb02d6c7bf552b1fc818aa4308fa0c2 100644 (file)
@@ -1399,7 +1399,6 @@ static int b44_open(struct net_device *dev)
        b44_init_rings(bp);
        b44_init_hw(bp);
 
-       netif_carrier_off(dev);
        b44_check_phy(bp);
 
        err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
@@ -1464,7 +1463,7 @@ static int b44_close(struct net_device *dev)
 #endif
        b44_halt(bp);
        b44_free_rings(bp);
-       netif_carrier_off(bp->dev);
+       netif_carrier_off(dev);
 
        spin_unlock_irq(&bp->lock);
 
@@ -2000,6 +1999,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
        dev->irq = pdev->irq;
        SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
 
+       netif_carrier_off(dev);
+
        err = b44_get_invariants(bp);
        if (err) {
                printk(KERN_ERR PFX "Problem fetching invariants of chip, "
index 2582d98ef5c3308c16214b75f520ec1abb1b97e4..4ff006c37626b92c8e80085480fc01f090da1cdb 100644 (file)
@@ -576,7 +576,7 @@ static int bond_update_speed_duplex(struct slave *slave)
        slave->duplex = DUPLEX_FULL;
 
        if (slave_dev->ethtool_ops) {
-               u32 res;
+               int res;
 
                if (!slave_dev->ethtool_ops->get_settings) {
                        return -1;
index 40ae36b20c9dea2811491e93e4de9ceb9d0c3ef5..7ef4b0434a3fa74cd438ce5d8abb45cc8ed5df22 100644 (file)
@@ -444,6 +444,7 @@ static int mv643xx_eth_receive_queue(struct net_device *dev)
                        netif_rx(skb);
 #endif
                }
+               dev->last_rx = jiffies;
        }
 
        return received_packets;
@@ -461,7 +462,7 @@ static int mv643xx_eth_receive_queue(struct net_device *dev)
  */
 
 static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id,
-                                                       struct pt_regs *regs)
+                                               struct pt_regs *regs)
 {
        struct net_device *dev = (struct net_device *)dev_id;
        struct mv643xx_private *mp = netdev_priv(dev);
@@ -1047,16 +1048,15 @@ static int mv643xx_poll(struct net_device *dev, int *budget)
 
 static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb)
 {
-        unsigned int frag;
-        skb_frag_t *fragp;
+       unsigned int frag;
+       skb_frag_t *fragp;
 
-        for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
-                fragp = &skb_shinfo(skb)->frags[frag];
-                if (fragp->size <= 8 && fragp->page_offset & 0x7)
-                        return 1;
-
-        }
-        return 0;
+       for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+               fragp = &skb_shinfo(skb)->frags[frag];
+               if (fragp->size <= 8 && fragp->page_offset & 0x7)
+                       return 1;
+       }
+       return 0;
 }
 
 
@@ -2137,26 +2137,26 @@ static void eth_port_set_multicast_list(struct net_device *dev)
         */
        if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) {
                for (table_index = 0; table_index <= 0xFC; table_index += 4) {
-                        /* Set all entries in DA filter special multicast
-                         * table (Ex_dFSMT)
-                         * Set for ETH_Q0 for now
-                         * Bits
-                         * 0     Accept=1, Drop=0
-                         * 3-1  Queue   ETH_Q0=0
-                         * 7-4  Reserved = 0;
-                         */
-                        mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
-
-                        /* Set all entries in DA filter other multicast
-                         * table (Ex_dFOMT)
-                         * Set for ETH_Q0 for now
-                         * Bits
-                         * 0     Accept=1, Drop=0
-                         * 3-1  Queue   ETH_Q0=0
-                         * 7-4  Reserved = 0;
-                         */
-                        mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
-               }
+                       /* Set all entries in DA filter special multicast
+                        * table (Ex_dFSMT)
+                        * Set for ETH_Q0 for now
+                        * Bits
+                        * 0      Accept=1, Drop=0
+                        * 3-1  Queue    ETH_Q0=0
+                        * 7-4  Reserved = 0;
+                        */
+                       mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
+
+                       /* Set all entries in DA filter other multicast
+                        * table (Ex_dFOMT)
+                        * Set for ETH_Q0 for now
+                        * Bits
+                        * 0      Accept=1, Drop=0
+                        * 3-1  Queue    ETH_Q0=0
+                        * 7-4  Reserved = 0;
+                        */
+                       mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
+               }
                return;
        }
 
@@ -2617,7 +2617,6 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
        struct eth_tx_desc *current_descriptor;
        struct eth_tx_desc *first_descriptor;
        u32 command;
-       unsigned long flags;
 
        /* Do not process Tx ring in case of Tx ring resource error */
        if (mp->tx_resource_err)
@@ -2634,8 +2633,6 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
                return ETH_ERROR;
        }
 
-       spin_lock_irqsave(&mp->lock, flags);
-
        mp->tx_ring_skbs++;
        BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
 
@@ -2685,15 +2682,11 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
                mp->tx_resource_err = 1;
                mp->tx_curr_desc_q = tx_first_desc;
 
-               spin_unlock_irqrestore(&mp->lock, flags);
-
                return ETH_QUEUE_LAST_RESOURCE;
        }
 
        mp->tx_curr_desc_q = tx_next_desc;
 
-       spin_unlock_irqrestore(&mp->lock, flags);
-
        return ETH_OK;
 }
 #else
@@ -2704,14 +2697,11 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
        int tx_desc_used;
        struct eth_tx_desc *current_descriptor;
        unsigned int command_status;
-       unsigned long flags;
 
        /* Do not process Tx ring in case of Tx ring resource error */
        if (mp->tx_resource_err)
                return ETH_QUEUE_FULL;
 
-       spin_lock_irqsave(&mp->lock, flags);
-
        mp->tx_ring_skbs++;
        BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size);
 
@@ -2742,12 +2732,9 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp,
        /* Check for ring index overlap in the Tx desc ring */
        if (tx_desc_curr == tx_desc_used) {
                mp->tx_resource_err = 1;
-
-               spin_unlock_irqrestore(&mp->lock, flags);
                return ETH_QUEUE_LAST_RESOURCE;
        }
 
-       spin_unlock_irqrestore(&mp->lock, flags);
        return ETH_OK;
 }
 #endif
@@ -2898,8 +2885,10 @@ static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp,
        p_pkt_info->return_info = mp->rx_skb[rx_curr_desc];
        p_pkt_info->l4i_chk = p_rx_desc->buf_size;
 
-       /* Clean the return info field to indicate that the packet has been */
-       /* moved to the upper layers                                        */
+       /*
+        * Clean the return info field to indicate that the
+        * packet has been moved to the upper layers
+        */
        mp->rx_skb[rx_curr_desc] = NULL;
 
        /* Update current index in data structure */
@@ -2980,7 +2969,7 @@ struct mv643xx_stats {
 };
 
 #define MV643XX_STAT(m) sizeof(((struct mv643xx_private *)0)->m), \
-                     offsetof(struct mv643xx_private, m)
+                                       offsetof(struct mv643xx_private, m)
 
 static const struct mv643xx_stats mv643xx_gstrings_stats[] = {
        { "rx_packets", MV643XX_STAT(stats.rx_packets) },
@@ -3131,9 +3120,8 @@ mv643xx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
        return 0;
 }
 
-static void
-mv643xx_get_drvinfo(struct net_device *netdev,
-                       struct ethtool_drvinfo *drvinfo)
+static void mv643xx_get_drvinfo(struct net_device *netdev,
+                               struct ethtool_drvinfo *drvinfo)
 {
        strncpy(drvinfo->driver,  mv643xx_driver_name, 32);
        strncpy(drvinfo->version, mv643xx_driver_version, 32);
@@ -3142,39 +3130,37 @@ mv643xx_get_drvinfo(struct net_device *netdev,
        drvinfo->n_stats = MV643XX_STATS_LEN;
 }
 
-static int 
-mv643xx_get_stats_count(struct net_device *netdev)
+static int mv643xx_get_stats_count(struct net_device *netdev)
 {
        return MV643XX_STATS_LEN;
 }
 
-static void 
-mv643xx_get_ethtool_stats(struct net_device *netdev, 
-               struct ethtool_stats *stats, uint64_t *data)
+static void mv643xx_get_ethtool_stats(struct net_device *netdev,
+                               struct ethtool_stats *stats, uint64_t *data)
 {
        struct mv643xx_private *mp = netdev->priv;
        int i;
 
        eth_update_mib_counters(mp);
 
-       for(i = 0; i < MV643XX_STATS_LEN; i++) {
+       for (i = 0; i < MV643XX_STATS_LEN; i++) {
                char *p = (char *)mp+mv643xx_gstrings_stats[i].stat_offset;     
-               data[i] = (mv643xx_gstrings_stats[i].sizeof_stat == 
+               data[i] = (mv643xx_gstrings_stats[i].sizeof_stat ==
                        sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p;
        }
 }
 
-static void 
-mv643xx_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data)
+static void mv643xx_get_strings(struct net_device *netdev, uint32_t stringset,
+                               uint8_t *data)
 {
        int i;
 
        switch(stringset) {
        case ETH_SS_STATS:
                for (i=0; i < MV643XX_STATS_LEN; i++) {
-                       memcpy(data + i * ETH_GSTRING_LEN, 
-                       mv643xx_gstrings_stats[i].stat_string,
-                       ETH_GSTRING_LEN);
+                       memcpy(data + i * ETH_GSTRING_LEN,
+                                       mv643xx_gstrings_stats[i].stat_string,
+                                       ETH_GSTRING_LEN);
                }
                break;
        }
index 89c46787676c9d9d3249597b38ce788a56fb5bc4..49b597cbc19a076e1ed2e737ff68b7b653922044 100644 (file)
@@ -3586,7 +3586,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
                txdp->Buffer_Pointer = (u64) pci_map_page
                    (sp->pdev, frag->page, frag->page_offset,
                     frag->size, PCI_DMA_TODEVICE);
-               txdp->Control_1 |= TXD_BUFFER0_SIZE(frag->size);
+               txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
                if (skb_shinfo(skb)->ufo_size)
                        txdp->Control_1 |= TXD_UFO_EN;
        }
index c8f6286dd35fd29e514654a69be5067fc0aca469..308f773ad566b17b2f394273fefb5f6d1507f652 100644 (file)
@@ -75,7 +75,7 @@ config HOSTAP_PCI
 
 config HOSTAP_CS
        tristate "Host AP driver for Prism2/2.5/3 PC Cards"
-       depends on PCMCIA!=n && HOSTAP
+       depends on PCMCIA && HOSTAP
        ---help---
        Host AP driver's version for Prism2/2.5/3 PC Cards.
 
index 8bf02763b5c72fc5ae116b113835cac1b8544c7d..6290c9f7e939c2b4b21c04d97879c231063e2b24 100644 (file)
@@ -2201,6 +2201,17 @@ static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
 #define SEARCH_SNAPSHOT 1
 
 #define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
+static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
+{
+       int i;
+       if (!priv->snapshot[0])
+               return;
+       for (i = 0; i < 0x30; i++)
+               kfree(priv->snapshot[i]);
+       priv->snapshot[0] = NULL;
+}
+
+#ifdef CONFIG_IPW2100_DEBUG_C3
 static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
 {
        int i;
@@ -2221,16 +2232,6 @@ static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
        return 1;
 }
 
-static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
-{
-       int i;
-       if (!priv->snapshot[0])
-               return;
-       for (i = 0; i < 0x30; i++)
-               kfree(priv->snapshot[i]);
-       priv->snapshot[0] = NULL;
-}
-
 static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
                                    size_t len, int mode)
 {
@@ -2269,6 +2270,7 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
 
        return ret;
 }
+#endif
 
 /*
  *
@@ -7112,11 +7114,17 @@ static int ipw2100_wx_set_txpow(struct net_device *dev,
 {
        struct ipw2100_priv *priv = ieee80211_priv(dev);
        int err = 0, value;
+       
+       if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
+               return -EINPROGRESS;
 
        if (priv->ieee->iw_mode != IW_MODE_ADHOC)
+               return 0;
+
+       if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
                return -EINVAL;
 
-       if (wrqu->txpower.disabled == 1 || wrqu->txpower.fixed == 0)
+       if (wrqu->txpower.fixed == 0)
                value = IPW_TX_POWER_DEFAULT;
        else {
                if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
@@ -7151,24 +7159,19 @@ static int ipw2100_wx_get_txpow(struct net_device *dev,
 
        struct ipw2100_priv *priv = ieee80211_priv(dev);
 
-       if (priv->ieee->iw_mode != IW_MODE_ADHOC) {
-               wrqu->power.disabled = 1;
-               return 0;
-       }
+       wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
 
        if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
-               wrqu->power.fixed = 0;
-               wrqu->power.value = IPW_TX_POWER_MAX_DBM;
-               wrqu->power.disabled = 1;
+               wrqu->txpower.fixed = 0;
+               wrqu->txpower.value = IPW_TX_POWER_MAX_DBM;
        } else {
-               wrqu->power.disabled = 0;
-               wrqu->power.fixed = 1;
-               wrqu->power.value = priv->tx_power;
+               wrqu->txpower.fixed = 1;
+               wrqu->txpower.value = priv->tx_power;
        }
 
-       wrqu->power.flags = IW_TXPOW_DBM;
+       wrqu->txpower.flags = IW_TXPOW_DBM;
 
-       IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->power.value);
+       IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->txpower.value);
 
        return 0;
 }
index 4c28e332ecc33c656e0b9d55372db514cd9d7798..916b24c544e2ec662521ca45bbb8386408f9b4d6 100644 (file)
@@ -8012,6 +8012,10 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init)
        else
                IPW_DEBUG_INFO("Auto adhoc creation disabled.\n");
 
+       priv->config &= ~CFG_STATIC_ESSID;
+       priv->essid_len = 0;
+       memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+
        if (disable) {
                priv->status |= STATUS_RF_KILL_SW;
                IPW_DEBUG_INFO("Radio disabled.\n");
@@ -11035,7 +11039,6 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        net_dev->set_multicast_list = ipw_net_set_multicast_list;
        net_dev->set_mac_address = ipw_net_set_mac_address;
        priv->wireless_data.spy_data = &priv->ieee->spy_data;
-       priv->wireless_data.ieee80211 = priv->ieee;
        net_dev->wireless_data = &priv->wireless_data;
        net_dev->wireless_handlers = &ipw_wx_handler_def;
        net_dev->ethtool_ops = &ipw_ethtool_ops;
@@ -11121,8 +11124,8 @@ static void ipw_pci_remove(struct pci_dev *pdev)
        /* Free MAC hash list for ADHOC */
        for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) {
                list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
-                       kfree(list_entry(p, struct ipw_ibss_seq, list));
                        list_del(p);
+                       kfree(list_entry(p, struct ipw_ibss_seq, list));
                }
        }
 
index b664708481cc8ace4cbfb0bd74f3884e64900830..3c128b692bce23135343064458b501749f7d0724 100644 (file)
@@ -261,13 +261,13 @@ orinoco_cs_config(dev_link_t *link)
                /* Note that the CIS values need to be rescaled */
                if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
                        if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                               DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+                               DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, cfg CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
                                if (!ignore_cis_vcc)
                                        goto next_entry;
                        }
                } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
                        if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                               DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
+                               DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, dflt CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
                                if(!ignore_cis_vcc)
                                        goto next_entry;
                        }
index 2f1289eebb3c5e597ec5ffa828606cdb1bd1ac85..222a1cc4aa28814a118c9424dbe2e2cb8deb5fa9 100644 (file)
@@ -11,8 +11,7 @@ config HOTPLUG_PCI
        ---help---
          Say Y here if you have a motherboard with a PCI Hotplug controller.
          This allows you to add and remove PCI cards while the machine is
-         powered up and running.  The file system pcihpfs must be mounted
-         in order to interact with any PCI Hotplug controllers.
+         powered up and running.
 
          To compile this driver as a module, choose M here: the
          module will be called pci_hotplug.
index 7e7f913ba7b9e47712a9dc6cfd0d4ca5764bbe89..317457dd401451b2797f8c8135165d983f09d5f1 100644 (file)
@@ -302,7 +302,7 @@ static int ibm_get_table_from_acpi(char **bufp)
        }
 
        package = (union acpi_object *) buffer.pointer;
-       if(!(package) ||
+       if (!(package) ||
                        (package->type != ACPI_TYPE_PACKAGE) ||
                        !(package->package.elements)) {
                err("%s:  Invalid APCI object\n", __FUNCTION__);
@@ -405,7 +405,7 @@ static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
        }
        info.hardware_id.value[sizeof(info.hardware_id.value) - 1] = '\0';
 
-       if(info.current_status && (info.valid & ACPI_VALID_HID) &&
+       if (info.current_status && (info.valid & ACPI_VALID_HID) &&
                        (!strcmp(info.hardware_id.value, IBM_HARDWARE_ID1) ||
                        !strcmp(info.hardware_id.value, IBM_HARDWARE_ID2))) {
                dbg("found hardware: %s, handle: %p\n", info.hardware_id.value,
@@ -449,13 +449,11 @@ static int __init ibm_acpiphp_init(void)
        }
 
        ibm_note.device = device;
-       status = acpi_install_notify_handler(
-                       ibm_acpi_handle,
-                       ACPI_DEVICE_NOTIFY,
-                       ibm_handle_events,
+       status = acpi_install_notify_handler(ibm_acpi_handle,
+                       ACPI_DEVICE_NOTIFY, ibm_handle_events,
                        &ibm_note);
        if (ACPI_FAILURE(status)) {
-               err("%s:  Failed to register notification handler\n",
+               err("%s: Failed to register notification handler\n",
                                __FUNCTION__);
                retval = -EBUSY;
                goto init_cleanup;
@@ -482,14 +480,13 @@ static void __exit ibm_acpiphp_exit(void)
        if (acpiphp_unregister_attention(&ibm_attention_info))
                err("%s: attention info deregistration failed", __FUNCTION__);
 
-          status = acpi_remove_notify_handler(
+       status = acpi_remove_notify_handler(
                           ibm_acpi_handle,
                           ACPI_DEVICE_NOTIFY,
                           ibm_handle_events);
-          if (ACPI_FAILURE(status))
-                  err("%s:  Notification handler removal failed\n",
-                                  __FUNCTION__);
-       // remove the /sys entries
+       if (ACPI_FAILURE(status))
+               err("%s: Notification handler removal failed\n", __FUNCTION__);
+       /* remove the /sys entries */
        if (sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr))
                err("%s: removal of sysfs file apci_table failed\n",
                                __FUNCTION__);
index aabf1e70b5280f70210c7f9efe840d3964ab1a31..dc59da675c0807e3913a1dbf420bf2d15817fbde 100644 (file)
@@ -235,12 +235,12 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
 {
        int rc = 0;
        struct slot *pslot;
-       u8 cmd;
+       u8 cmd = 0x00;     /* avoid compiler warning */
 
        debug("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n",
                        (ulong) hotplug_slot, value);
        ibmphp_lock_operations();
-       cmd = 0x00;     // avoid compiler warning
+
 
        if (hotplug_slot) {
                switch (value) {
index 7d93dbaf628deda9dc32811b5c0ed95c023ea500..3eefe2cec72d1aef2ad849820fd3b683d7704645 100644 (file)
@@ -103,13 +103,13 @@ static struct slot *find_slot(struct device_node *dn)
        struct list_head *tmp, *n;
        struct slot *slot;
 
-        list_for_each_safe(tmp, n, &rpaphp_slot_head) {
-                slot = list_entry(tmp, struct slot, rpaphp_slot_list);
-                if (slot->dn == dn)
-                        return slot;
-        }
+       list_for_each_safe(tmp, n, &rpaphp_slot_head) {
+               slot = list_entry(tmp, struct slot, rpaphp_slot_list);
+               if (slot->dn == dn)
+                       return slot;
+       }
 
-        return NULL;
+       return NULL;
 }
 
 static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent,
@@ -126,9 +126,9 @@ static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent,
        return NULL;
 }
 
-static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
+static void dlpar_pci_add_bus(struct device_node *dn)
 {
-       struct pci_dn *pdn = dn->data;
+       struct pci_dn *pdn = PCI_DN(dn);
        struct pci_controller *phb = pdn->phb;
        struct pci_dev *dev = NULL;
 
@@ -139,52 +139,52 @@ static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
        if (!dev) {
                printk(KERN_ERR "%s: failed to create pci dev for %s\n",
                                __FUNCTION__, dn->full_name);
-               return NULL;
+               return;
        }
 
        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
            dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
                of_scan_pci_bridge(dn, dev);
 
-       rpaphp_init_new_devs(dev->subordinate);
+       pcibios_fixup_new_pci_devices(dev->subordinate,0);
 
        /* Claim new bus resources */
        pcibios_claim_one_bus(dev->bus);
 
        /* ioremap() for child bus, which may or may not succeed */
-       (void) remap_bus_range(dev->bus);
+       remap_bus_range(dev->subordinate);
 
        /* Add new devices to global lists.  Register in proc, sysfs. */
        pci_bus_add_devices(phb->bus);
-
-       /* Confirm new bridge dev was created */
-       dev = dlpar_find_new_dev(phb->bus, dn);
-       if (dev) {
-               if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
-                       printk(KERN_ERR "%s: unexpected header type %d\n",
-                               __FUNCTION__, dev->hdr_type);
-                       return NULL;
-               }
-       }
-
-       return dev;
 }
 
 static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
 {
        struct pci_dev *dev;
+       struct pci_controller *phb;
 
-       if (rpaphp_find_pci_bus(dn))
+       if (pcibios_find_pci_bus(dn))
                return -EINVAL;
 
        /* Add pci bus */
-       dev = dlpar_pci_add_bus(dn);
+       dlpar_pci_add_bus(dn);
+
+       /* Confirm new bridge dev was created */
+       phb = PCI_DN(dn)->phb;
+       dev = dlpar_find_new_dev(phb->bus, dn);
+
        if (!dev) {
                printk(KERN_ERR "%s: unable to add bus %s\n", __FUNCTION__,
                        drc_name);
                return -EIO;
        }
 
+       if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+               printk(KERN_ERR "%s: unexpected header type %d, unable to add bus %s\n",
+                       __FUNCTION__, dev->hdr_type, drc_name);
+               return -EIO;
+       }
+
        /* Add hotplug slot */
        if (rpaphp_add_slot(dn)) {
                printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
@@ -221,13 +221,13 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
        struct pci_dn *pdn;
        int rc = 0;
 
-       if (!rpaphp_find_pci_bus(dn))
+       if (!pcibios_find_pci_bus(dn))
                return -EINVAL;
 
        slot = find_slot(dn);
        if (slot) {
                /* Remove hotplug slot */
-               if (rpaphp_remove_slot(slot)) {
+               if (rpaphp_deregister_slot(slot)) {
                        printk(KERN_ERR
                                "%s: unable to remove hotplug slot %s\n",
                                __FUNCTION__, drc_name);
@@ -366,21 +366,25 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
        struct pci_bus *bus;
        struct slot *slot;
 
-       bus = rpaphp_find_pci_bus(dn);
+       bus = pcibios_find_pci_bus(dn);
        if (!bus)
                return -EINVAL;
 
        slot = find_slot(dn);
        if (slot) {
                /* Remove hotplug slot */
-               if (rpaphp_remove_slot(slot)) {
+               if (rpaphp_deregister_slot(slot)) {
                        printk(KERN_ERR
                                "%s: unable to remove hotplug slot %s\n",
                                __FUNCTION__, drc_name);
                        return -EIO;
                }
        } else {
-               rpaphp_unconfig_pci_adapter(bus);
+               struct pci_dev *dev, *tmp;
+               list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
+                       eeh_remove_bus_device(dev);
+                       pci_remove_bus_device(dev);
+               }
        }
 
        if (unmap_bus_range(bus)) {
index 57ea71a7bda5049210b418cfb357a703a945a85c..310b6186c0e5f45aa19f11654a49c38fcb839458 100644 (file)
@@ -88,16 +88,10 @@ extern int num_slots;
 /* function prototypes */
 
 /* rpaphp_pci.c */
-extern struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn);
-extern int rpaphp_claim_resource(struct pci_dev *dev, int resource);
 extern int rpaphp_enable_pci_slot(struct slot *slot);
-extern int register_pci_slot(struct slot *slot);
+extern int rpaphp_register_pci_slot(struct slot *slot);
 extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value);
-extern void rpaphp_init_new_devs(struct pci_bus *bus);
-extern void rpaphp_eeh_init_nodes(struct device_node *dn);
-
-extern int rpaphp_config_pci_adapter(struct pci_bus *bus);
-extern int rpaphp_unconfig_pci_adapter(struct pci_bus *bus);
+extern int rpaphp_get_sensor_state(struct slot *slot, int *state);
 
 /* rpaphp_core.c */
 extern int rpaphp_add_slot(struct device_node *dn);
@@ -108,8 +102,8 @@ extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
 /* rpaphp_slot.c */
 extern void dealloc_slot_struct(struct slot *slot);
 extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain);
-extern int register_slot(struct slot *slot);
-extern int deregister_slot(struct slot *slot);
+extern int rpaphp_register_slot(struct slot *slot);
+extern int rpaphp_deregister_slot(struct slot *slot);
 extern int rpaphp_get_power_status(struct slot *slot, u8 * value);
 extern int rpaphp_set_attention_status(struct slot *slot, u8 status);
        
index cf075c34b578c4e4048b47da205efb882acff96f..6e79f5675b0d9b804a8c8465e07f0884d59dc63a 100644 (file)
@@ -56,25 +56,6 @@ MODULE_LICENSE("GPL");
 
 module_param(debug, bool, 0644);
 
-static int enable_slot(struct hotplug_slot *slot);
-static int disable_slot(struct hotplug_slot *slot);
-static int set_attention_status(struct hotplug_slot *slot, u8 value);
-static int get_power_status(struct hotplug_slot *slot, u8 * value);
-static int get_attention_status(struct hotplug_slot *slot, u8 * value);
-static int get_adapter_status(struct hotplug_slot *slot, u8 * value);
-static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
-
-struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
-       .owner = THIS_MODULE,
-       .enable_slot = enable_slot,
-       .disable_slot = disable_slot,
-       .set_attention_status = set_attention_status,
-       .get_power_status = get_power_status,
-       .get_attention_status = get_attention_status,
-       .get_adapter_status = get_adapter_status,
-       .get_max_bus_speed = get_max_bus_speed,
-};
-
 static int rpaphp_get_attention_status(struct slot *slot)
 {
        return slot->hotplug_slot->info->attention_status;
@@ -196,11 +177,6 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
        return 0;
 }
 
-int rpaphp_remove_slot(struct slot *slot)
-{
-       return deregister_slot(slot);
-}
-
 static int get_children_props(struct device_node *dn, int **drc_indexes,
                int **drc_names, int **drc_types, int **drc_power_domains)
 {
@@ -307,13 +283,15 @@ static int is_php_dn(struct device_node *dn, int **indexes, int **names,
        return 0;
 }
 
-/****************************************************************
+/**
+ * rpaphp_add_slot -- add hotplug or dlpar slot
+ *
  *     rpaphp not only registers PCI hotplug slots(HOTPLUG), 
  *     but also logical DR slots(EMBEDDED).
  *     HOTPLUG slot: An adapter can be physically added/removed. 
  *     EMBEDDED slot: An adapter can be logically removed/added
  *               from/to a partition with the slot.
- ***************************************************************/
+ */
 int rpaphp_add_slot(struct device_node *dn)
 {
        struct slot *slot;
@@ -344,7 +322,7 @@ int rpaphp_add_slot(struct device_node *dn)
                        dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
                                        indexes[i + 1], name, type);
 
-                       retval = register_pci_slot(slot);
+                       retval = rpaphp_register_pci_slot(slot);
                }
        }
 exit:
@@ -393,53 +371,85 @@ static void __exit rpaphp_exit(void)
        cleanup_slots();
 }
 
-static int enable_slot(struct hotplug_slot *hotplug_slot)
+static int __enable_slot(struct slot *slot)
 {
-       int retval = 0;
-       struct slot *slot = (struct slot *)hotplug_slot->private;
+       int state;
+       int retval;
 
-       if (slot->state == CONFIGURED) {
-               dbg("%s: %s is already enabled\n", __FUNCTION__, slot->name);
-               goto exit;
+       if (slot->state == CONFIGURED)
+               return 0;
+
+       retval = rpaphp_get_sensor_state(slot, &state);
+       if (retval)
+               return retval;
+
+       if (state == PRESENT) {
+               pcibios_add_pci_devices(slot->bus);
+               slot->state = CONFIGURED;
+       } else if (state == EMPTY) {
+               slot->state = EMPTY;
+       } else {
+               err("%s: slot[%s] is in invalid state\n", __FUNCTION__, slot->name);
+               slot->state = NOT_VALID;
+               return -EINVAL;
        }
+       return 0;
+}
+
+static int enable_slot(struct hotplug_slot *hotplug_slot)
+{
+       int retval;
+       struct slot *slot = (struct slot *)hotplug_slot->private;
 
-       dbg("ENABLING SLOT %s\n", slot->name);
        down(&rpaphp_sem);
-       retval = rpaphp_enable_pci_slot(slot);
+       retval = __enable_slot(slot);
        up(&rpaphp_sem);
-exit:
-       dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+
        return retval;
 }
 
-static int disable_slot(struct hotplug_slot *hotplug_slot)
+static int __disable_slot(struct slot *slot)
 {
-       int retval = -EINVAL;
-       struct slot *slot = (struct slot *)hotplug_slot->private;
+       struct pci_dev *dev, *tmp;
 
-       dbg("%s - Entry: slot[%s]\n", __FUNCTION__, slot->name);
+       if (slot->state == NOT_CONFIGURED)
+               return -EINVAL;
 
-       if (slot->state == NOT_CONFIGURED) {
-               dbg("%s: %s is already disabled\n", __FUNCTION__, slot->name);
-               goto exit;
+       list_for_each_entry_safe(dev, tmp, &slot->bus->devices, bus_list) {
+               eeh_remove_bus_device(dev);
+               pci_remove_bus_device(dev);
        }
 
-       dbg("DISABLING SLOT %s\n", slot->name);
+       slot->state = NOT_CONFIGURED;
+       return 0;
+}
+
+static int disable_slot(struct hotplug_slot *hotplug_slot)
+{
+       struct slot *slot = (struct slot *)hotplug_slot->private;
+       int retval;
+
        down(&rpaphp_sem);
-       retval = rpaphp_unconfig_pci_adapter(slot->bus);
+       retval = __disable_slot (slot);
        up(&rpaphp_sem);
-       slot->state = NOT_CONFIGURED;
-       info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__,
-            slot->name);
-exit:
-       dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+
        return retval;
 }
 
+struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
+       .owner = THIS_MODULE,
+       .enable_slot = enable_slot,
+       .disable_slot = disable_slot,
+       .set_attention_status = set_attention_status,
+       .get_power_status = get_power_status,
+       .get_attention_status = get_attention_status,
+       .get_adapter_status = get_adapter_status,
+       .get_max_bus_speed = get_max_bus_speed,
+};
+
 module_init(rpaphp_init);
 module_exit(rpaphp_exit);
 
 EXPORT_SYMBOL_GPL(rpaphp_add_slot);
-EXPORT_SYMBOL_GPL(rpaphp_remove_slot);
 EXPORT_SYMBOL_GPL(rpaphp_slot_head);
 EXPORT_SYMBOL_GPL(rpaphp_get_drc_props);
index 396b54b0c8474cc6fa38fc04aba030c073a5641e..6f6cbede5135cde8cd7f9a8a2b68c6a77b7c8ea9 100644 (file)
 #include "../pci.h"            /* for pci_add_new_bus */
 #include "rpaphp.h"
 
-static struct pci_bus *find_bus_among_children(struct pci_bus *bus,
-                                       struct device_node *dn)
-{
-       struct pci_bus *child = NULL;
-       struct list_head *tmp;
-       struct device_node *busdn;
-
-       busdn = pci_bus_to_OF_node(bus);
-       if (busdn == dn)
-               return bus;
-
-       list_for_each(tmp, &bus->children) {
-               child = find_bus_among_children(pci_bus_b(tmp), dn);
-               if (child)
-                       break;
-       }
-       return child;
-}
-
-struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn)
-{
-       struct pci_dn *pdn = dn->data;
-
-       if (!pdn  || !pdn->phb || !pdn->phb->bus)
-               return NULL;
-
-       return find_bus_among_children(pdn->phb->bus, dn);
-}
-EXPORT_SYMBOL_GPL(rpaphp_find_pci_bus);
-
-static int rpaphp_get_sensor_state(struct slot *slot, int *state)
+int rpaphp_get_sensor_state(struct slot *slot, int *state)
 {
        int rc;
        int setlevel;
@@ -120,7 +90,7 @@ int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value)
                        /* config/unconfig adapter */
                        *value = slot->state;
                } else {
-                       bus = rpaphp_find_pci_bus(slot->dn);
+                       bus = pcibios_find_pci_bus(slot->dn);
                        if (bus && !list_empty(&bus->devices))
                                *value = CONFIGURED;
                        else
@@ -131,140 +101,6 @@ exit:
        return rc;
 }
 
-/* Must be called before pci_bus_add_devices */
-void rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
-{
-       struct pci_dev *dev;
-
-       list_for_each_entry(dev, &bus->devices, bus_list) {
-               /*
-                * Skip already-present devices (which are on the
-                * global device list.)
-                */
-               if (list_empty(&dev->global_list)) {
-                       int i;
-                       
-                       /* Need to setup IOMMU tables */
-                       ppc_md.iommu_dev_setup(dev);
-
-                       if(fix_bus)
-                               pcibios_fixup_device_resources(dev, bus);
-                       pci_read_irq_line(dev);
-                       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-                               struct resource *r = &dev->resource[i];
-
-                               if (r->parent || !r->start || !r->flags)
-                                       continue;
-                               pci_claim_resource(dev, i);
-                       }
-               }
-       }
-}
-
-static void rpaphp_eeh_add_bus_device(struct pci_bus *bus)
-{
-       struct pci_dev *dev;
-
-       list_for_each_entry(dev, &bus->devices, bus_list) {
-               eeh_add_device_late(dev);
-               if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-                       struct pci_bus *subbus = dev->subordinate;
-                       if (subbus)
-                               rpaphp_eeh_add_bus_device (subbus);
-               }
-       }
-}
-
-static int rpaphp_pci_config_bridge(struct pci_dev *dev)
-{
-       u8 sec_busno;
-       struct pci_bus *child_bus;
-       struct pci_dev *child_dev;
-
-       dbg("Enter %s:  BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev));
-
-       /* get busno of downstream bus */
-       pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
-               
-       /* add to children of PCI bridge dev->bus */
-       child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
-       if (!child_bus) {
-               err("%s: could not add second bus\n", __FUNCTION__);
-               return -EIO;
-       }
-       sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
-       /* do pci_scan_child_bus */
-       pci_scan_child_bus(child_bus);
-
-       list_for_each_entry(child_dev, &child_bus->devices, bus_list) {
-               eeh_add_device_late(child_dev);
-       }
-
-        /* fixup new pci devices without touching bus struct */
-       rpaphp_fixup_new_pci_devices(child_bus, 0);
-
-       /* Make the discovered devices available */
-       pci_bus_add_devices(child_bus);
-       return 0;
-}
-
-void rpaphp_init_new_devs(struct pci_bus *bus)
-{
-       rpaphp_fixup_new_pci_devices(bus, 0);
-       rpaphp_eeh_add_bus_device(bus);
-}
-EXPORT_SYMBOL_GPL(rpaphp_init_new_devs);
-
-/*****************************************************************************
- rpaphp_pci_config_slot() will  configure all devices under the
- given slot->dn and return the the first pci_dev.
- *****************************************************************************/
-static struct pci_dev *
-rpaphp_pci_config_slot(struct pci_bus *bus)
-{
-       struct device_node *dn = pci_bus_to_OF_node(bus);
-       struct pci_dev *dev = NULL;
-       int slotno;
-       int num;
-
-       dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name);
-       if (!dn || !dn->child)
-               return NULL;
-
-       if (_machine == PLATFORM_PSERIES_LPAR) {
-               of_scan_bus(dn, bus);
-               if (list_empty(&bus->devices)) {
-                       err("%s: No new device found\n", __FUNCTION__);
-                       return NULL;
-               }
-
-               rpaphp_init_new_devs(bus);
-               pci_bus_add_devices(bus);
-               dev = list_entry(&bus->devices, struct pci_dev, bus_list);
-       } else {
-               slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
-
-               /* pci_scan_slot should find all children */
-               num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
-               if (num) {
-                       rpaphp_fixup_new_pci_devices(bus, 1);
-                       pci_bus_add_devices(bus);
-               }
-               if (list_empty(&bus->devices)) {
-                       err("%s: No new device found\n", __FUNCTION__);
-                       return NULL;
-               }
-               list_for_each_entry(dev, &bus->devices, bus_list) {
-                       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
-                               rpaphp_pci_config_bridge(dev);
-
-                       rpaphp_eeh_add_bus_device(bus);
-               }
-       }
-
-       return dev;
-}
-
 static void print_slot_pci_funcs(struct pci_bus *bus)
 {
        struct device_node *dn;
@@ -280,60 +116,6 @@ static void print_slot_pci_funcs(struct pci_bus *bus)
        return;
 }
 
-int rpaphp_config_pci_adapter(struct pci_bus *bus)
-{
-       struct device_node *dn = pci_bus_to_OF_node(bus);
-       struct pci_dev *dev;
-       int rc = -ENODEV;
-
-       dbg("Entry %s: slot[%s]\n", __FUNCTION__, dn->full_name);
-       if (!dn)
-               goto exit;
-
-       eeh_add_device_tree_early(dn);
-       dev = rpaphp_pci_config_slot(bus);
-       if (!dev) {
-               err("%s: can't find any devices.\n", __FUNCTION__);
-               goto exit;
-       }
-       print_slot_pci_funcs(bus);
-       rc = 0;
-exit:
-       dbg("Exit %s:  rc=%d\n", __FUNCTION__, rc);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(rpaphp_config_pci_adapter);
-
-static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev)
-{
-       eeh_remove_device(dev);
-       if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-               struct pci_bus *bus = dev->subordinate;
-               struct list_head *ln;
-               if (!bus)
-                       return; 
-               for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
-                       struct pci_dev *pdev = pci_dev_b(ln);
-                       if (pdev)
-                               rpaphp_eeh_remove_bus_device(pdev);
-               }
-
-       }
-       return;
-}
-
-int rpaphp_unconfig_pci_adapter(struct pci_bus *bus)
-{
-       struct pci_dev *dev, *tmp;
-
-       list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
-               rpaphp_eeh_remove_bus_device(dev);
-               pci_remove_bus_device(dev);
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(rpaphp_unconfig_pci_adapter);
-
 static int setup_pci_hotplug_slot_info(struct slot *slot)
 {
        struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info;
@@ -370,7 +152,7 @@ static int setup_pci_slot(struct slot *slot)
        struct pci_bus *bus;
 
        BUG_ON(!dn);
-       bus = rpaphp_find_pci_bus(dn);
+       bus = pcibios_find_pci_bus(dn);
        if (!bus) {
                err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name);
                goto exit_rc;
@@ -395,10 +177,7 @@ static int setup_pci_slot(struct slot *slot)
                if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) {
                        dbg("%s CONFIGURING pci adapter in slot[%s]\n",  
                                __FUNCTION__, slot->name);
-                       if (rpaphp_config_pci_adapter(slot->bus)) {
-                               err("%s: CONFIG pci adapter failed\n", __FUNCTION__);
-                               goto exit_rc;           
-                       }
+                       pcibios_add_pci_devices(slot->bus);
 
                } else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) {
                        err("%s: slot[%s]'s adapter_status is NOT_VALID.\n",
@@ -420,7 +199,7 @@ exit_rc:
        return -EINVAL;
 }
 
-int register_pci_slot(struct slot *slot)
+int rpaphp_register_pci_slot(struct slot *slot)
 {
        int rc = -EINVAL;
 
@@ -428,42 +207,8 @@ int register_pci_slot(struct slot *slot)
                goto exit_rc;
        if (setup_pci_slot(slot))
                goto exit_rc;
-       rc = register_slot(slot);
+       rc = rpaphp_register_slot(slot);
 exit_rc:
        return rc;
 }
 
-int rpaphp_enable_pci_slot(struct slot *slot)
-{
-       int retval = 0, state;
-
-       retval = rpaphp_get_sensor_state(slot, &state);
-       if (retval)
-               goto exit;
-       dbg("%s: sensor state[%d]\n", __FUNCTION__, state);
-       /* if slot is not empty, enable the adapter */
-       if (state == PRESENT) {
-               dbg("%s : slot[%s] is occupied.\n", __FUNCTION__, slot->name);
-               retval = rpaphp_config_pci_adapter(slot->bus);
-               if (!retval) {
-                       slot->state = CONFIGURED;
-                       info("%s: devices in slot[%s] configured\n",
-                                       __FUNCTION__, slot->name);
-               } else {
-                       slot->state = NOT_CONFIGURED;
-                       dbg("%s: no pci_dev struct for adapter in slot[%s]\n",
-                           __FUNCTION__, slot->name);
-               }
-       } else if (state == EMPTY) {
-               dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name);
-               slot->state = EMPTY;
-       } else {
-               err("%s: slot[%s] is in invalid state\n", __FUNCTION__,
-                   slot->name);
-               slot->state = NOT_VALID;
-               retval = -EINVAL;
-       }
-exit:
-       dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
-       return retval;
-}
index daa89ae57123b52b97c0c4678c41867118ed39f9..04cc1e7275ce1c57cb78a768ed6808b88cba8124 100644 (file)
 
 static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf)
 {
-        char *value;
-        int retval = -ENOENT;
+       char *value;
+       int retval = -ENOENT;
        struct slot *slot = (struct slot *)php_slot->private;
 
        if (!slot)
                return retval;
 
-        value = slot->location;
-        retval = sprintf (buf, "%s\n", value);
-        return retval;
+       value = slot->location;
+       retval = sprintf (buf, "%s\n", value);
+       return retval;
 }
 
 static struct hotplug_slot_attribute hotplug_slot_attr_location = {
@@ -137,7 +137,7 @@ static int is_registered(struct slot *slot)
        return 0;
 }
 
-int deregister_slot(struct slot *slot)
+int rpaphp_deregister_slot(struct slot *slot)
 {
        int retval = 0;
        struct hotplug_slot *php_slot = slot->hotplug_slot;
@@ -160,7 +160,7 @@ int deregister_slot(struct slot *slot)
        return retval;
 }
 
-int register_slot(struct slot *slot)
+int rpaphp_register_slot(struct slot *slot)
 {
        int retval;
 
@@ -169,7 +169,7 @@ int register_slot(struct slot *slot)
                slot->power_domain, slot->type);
        /* should not try to register the same slot twice */
        if (is_registered(slot)) { /* should't be here */
-               err("register_slot: slot[%s] is already registered\n", slot->name);
+               err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name);
                rpaphp_release_slot(slot->hotplug_slot);
                return -EAGAIN;
        }       
index ce0e9b6ce83378fa416e9f6ed46a7562a0c64689..7d6f521d02ea128adf2fa0472f9afcd093186476 100644 (file)
@@ -95,6 +95,7 @@ struct controller {
        u8 function;
        u8 slot_device_offset;
        u8 add_support;
+       u32 pcix_misc2_reg;     /* for amd pogo errata */
        enum pci_bus_speed speed;
        u32 first_slot;         /* First physical slot number */
        u8 slot_bus;            /* Bus where the slots handled by this controller sit */
@@ -113,6 +114,26 @@ struct hotplug_params {
 
 /* Define AMD SHPC ID  */
 #define PCI_DEVICE_ID_AMD_GOLAM_7450   0x7450 
+#define PCI_DEVICE_ID_AMD_POGO_7458    0x7458
+
+/* AMD PCIX bridge registers */
+
+#define PCIX_MEM_BASE_LIMIT_OFFSET     0x1C
+#define PCIX_MISCII_OFFSET             0x48
+#define PCIX_MISC_BRIDGE_ERRORS_OFFSET 0x80
+
+/* AMD PCIX_MISCII masks and offsets */
+#define PERRNONFATALENABLE_MASK                0x00040000
+#define PERRFATALENABLE_MASK           0x00080000
+#define PERRFLOODENABLE_MASK           0x00100000
+#define SERRNONFATALENABLE_MASK                0x00200000
+#define SERRFATALENABLE_MASK           0x00400000
+
+/* AMD PCIX_MISC_BRIDGE_ERRORS masks and offsets */
+#define PERR_OBSERVED_MASK             0x00000001
+
+/* AMD PCIX_MEM_BASE_LIMIT masks */
+#define RSE_MASK                       0x40000000
 
 #define INT_BUTTON_IGNORE              0
 #define INT_PRESENCE_ON                        1
@@ -333,6 +354,79 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl)
        return retval;
 }
 
+static inline void amd_pogo_errata_save_misc_reg(struct slot *p_slot)
+{
+       u32 pcix_misc2_temp;
+
+       /* save MiscII register */
+       pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, &pcix_misc2_temp);
+
+       p_slot->ctrl->pcix_misc2_reg = pcix_misc2_temp;
+
+       /* clear SERR/PERR enable bits */
+       pcix_misc2_temp &= ~SERRFATALENABLE_MASK;
+       pcix_misc2_temp &= ~SERRNONFATALENABLE_MASK;
+       pcix_misc2_temp &= ~PERRFLOODENABLE_MASK;
+       pcix_misc2_temp &= ~PERRFATALENABLE_MASK;
+       pcix_misc2_temp &= ~PERRNONFATALENABLE_MASK;
+       pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp);
+}
+
+static inline void amd_pogo_errata_restore_misc_reg(struct slot *p_slot)
+{
+       u32 pcix_misc2_temp;
+       u32 pcix_bridge_errors_reg;
+       u32 pcix_mem_base_reg;
+       u8  perr_set;
+       u8  rse_set;
+
+       /* write-one-to-clear Bridge_Errors[ PERR_OBSERVED ] */
+       pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MISC_BRIDGE_ERRORS_OFFSET, &pcix_bridge_errors_reg);
+       perr_set = pcix_bridge_errors_reg & PERR_OBSERVED_MASK;
+       if (perr_set) {
+               dbg ("%s  W1C: Bridge_Errors[ PERR_OBSERVED = %08X]\n",__FUNCTION__ , perr_set);
+
+               pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISC_BRIDGE_ERRORS_OFFSET, perr_set);
+       }
+
+       /* write-one-to-clear Memory_Base_Limit[ RSE ] */
+       pci_read_config_dword(p_slot->ctrl->pci_dev, PCIX_MEM_BASE_LIMIT_OFFSET, &pcix_mem_base_reg);
+       rse_set = pcix_mem_base_reg & RSE_MASK;
+       if (rse_set) {
+               dbg ("%s  W1C: Memory_Base_Limit[ RSE ]\n",__FUNCTION__ );
+
+               pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MEM_BASE_LIMIT_OFFSET, rse_set);
+       }
+       /* restore MiscII register */
+       pci_read_config_dword( p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, &pcix_misc2_temp );
+
+       if (p_slot->ctrl->pcix_misc2_reg & SERRFATALENABLE_MASK)
+               pcix_misc2_temp |= SERRFATALENABLE_MASK;
+       else
+               pcix_misc2_temp &= ~SERRFATALENABLE_MASK;
+
+       if (p_slot->ctrl->pcix_misc2_reg & SERRNONFATALENABLE_MASK)
+               pcix_misc2_temp |= SERRNONFATALENABLE_MASK;
+       else
+               pcix_misc2_temp &= ~SERRNONFATALENABLE_MASK;
+
+       if (p_slot->ctrl->pcix_misc2_reg & PERRFLOODENABLE_MASK)
+               pcix_misc2_temp |= PERRFLOODENABLE_MASK;
+       else
+               pcix_misc2_temp &= ~PERRFLOODENABLE_MASK;
+
+       if (p_slot->ctrl->pcix_misc2_reg & PERRFATALENABLE_MASK)
+               pcix_misc2_temp |= PERRFATALENABLE_MASK;
+       else
+               pcix_misc2_temp &= ~PERRFATALENABLE_MASK;
+
+       if (p_slot->ctrl->pcix_misc2_reg & PERRNONFATALENABLE_MASK)
+               pcix_misc2_temp |= PERRNONFATALENABLE_MASK;
+       else
+               pcix_misc2_temp &= ~PERRNONFATALENABLE_MASK;
+       pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp);
+}
+
 #define SLOT_NAME_SIZE 10
 
 static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
index 25ccb0e475936b93e1fbda46d3b5154fa98d6e16..643252d9bf3b61e0b2333a082761a09950461c38 100644 (file)
@@ -894,7 +894,17 @@ int shpchp_enable_slot (struct slot *p_slot)
        dbg("%s: p_slot->pwr_save %x\n", __FUNCTION__, p_slot->pwr_save);
        p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 
-       rc = board_added(p_slot);
+       if(((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) ||
+           (p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458))
+            && p_slot->ctrl->num_slots == 1) {
+               /* handle amd pogo errata; this must be done before enable  */
+               amd_pogo_errata_save_misc_reg(p_slot);
+               rc = board_added(p_slot);
+               /* handle amd pogo errata; this must be done after enable  */
+               amd_pogo_errata_restore_misc_reg(p_slot);
+       } else
+               rc = board_added(p_slot);
+
        if (rc) {
                p_slot->hpc_ops->get_adapter_status(p_slot,
                                &(p_slot->presence_save));
index 202b7507a357092906680bd9e937e7882e428324..48723d6fa60f249343ee4bc7b065aed0150d8c01 100644 (file)
@@ -137,6 +137,8 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
                break;
        }
 }
+#else
+#define set_msi_affinity NULL
 #endif /* CONFIG_SMP */
 
 static void mask_MSI_irq(unsigned int vector)
@@ -214,7 +216,7 @@ static struct hw_interrupt_type msix_irq_type = {
        .disable        = mask_MSI_irq,
        .ack            = mask_MSI_irq,
        .end            = end_msi_irq_w_maskbit,
-       .set_affinity   = set_msi_irq_affinity
+       .set_affinity   = set_msi_affinity
 };
 
 /*
@@ -230,7 +232,7 @@ static struct hw_interrupt_type msi_irq_w_maskbit_type = {
        .disable        = mask_MSI_irq,
        .ack            = mask_MSI_irq,
        .end            = end_msi_irq_w_maskbit,
-       .set_affinity   = set_msi_irq_affinity
+       .set_affinity   = set_msi_affinity
 };
 
 /*
@@ -246,7 +248,7 @@ static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
        .disable        = do_nothing,
        .ack            = do_nothing,
        .end            = end_msi_irq_wo_maskbit,
-       .set_affinity   = set_msi_irq_affinity
+       .set_affinity   = set_msi_affinity
 };
 
 static void msi_data_init(struct msg_data *msi_data,
@@ -416,7 +418,9 @@ static void attach_msi_entry(struct msi_desc *entry, int vector)
 
 static void irq_handler_init(int cap_id, int pos, int mask)
 {
-       spin_lock(&irq_desc[pos].lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&irq_desc[pos].lock, flags);
        if (cap_id == PCI_CAP_ID_MSIX)
                irq_desc[pos].handler = &msix_irq_type;
        else {
@@ -425,7 +429,7 @@ static void irq_handler_init(int cap_id, int pos, int mask)
                else
                        irq_desc[pos].handler = &msi_irq_w_maskbit_type;
        }
-       spin_unlock(&irq_desc[pos].lock);
+       spin_unlock_irqrestore(&irq_desc[pos].lock, flags);
 }
 
 static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
index 402136a5c9e43c1af7ff107e8e20cd992657c30c..4ac52d441e472d86e9e15e0f48d761e6a3c51223 100644 (file)
@@ -22,12 +22,6 @@ extern int vector_irq[NR_VECTORS];
 extern void (*interrupt[NR_IRQS])(void);
 extern int pci_vector_resources(int last, int nr_released);
 
-#ifdef CONFIG_SMP
-#define set_msi_irq_affinity   set_msi_affinity
-#else
-#define set_msi_irq_affinity   NULL
-#endif
-
 /*
  * MSI-X Address Register
  */
index d2a633efa10ab0822c3f8a6431a98f413c3b24bb..d2d1879166436cfee7f82c6e0fa0493cfdc8c3b0 100644 (file)
@@ -163,6 +163,7 @@ int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
        return __pci_bus_find_cap(bus, devfn, hdr_type & 0x7f, cap);
 }
 
+#if 0
 /**
  * pci_find_ext_capability - Find an extended capability
  * @dev: PCI device to query
@@ -210,6 +211,7 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap)
 
        return 0;
 }
+#endif  /*  0  */
 
 /**
  * pci_find_parent_resource - return resource region of parent bus of given region
index 50d6685dcbcce801682c9600a81be2a98f90f8a1..ea9277b7f8994120aed0b3d058da25de31e99c57 100644 (file)
@@ -112,6 +112,7 @@ pci_claim_resource(struct pci_dev *dev, int resource)
 
        return err;
 }
+EXPORT_SYMBOL_GPL(pci_claim_resource);
 
 int pci_assign_resource(struct pci_dev *dev, int resno)
 {
index 69ed77fcb71f9076213761b2a18025a16408d406..7955ebe8e1e8d6d8be83c5f659efb878c8cedb85 100644 (file)
@@ -37,13 +37,13 @@ config AIC79XX_CMDS_PER_DEVICE
 config AIC79XX_RESET_DELAY_MS
        int "Initial bus reset delay in milli-seconds"
        depends on SCSI_AIC79XX
-       default "15000"
+       default "5000"
        ---help---
        The number of milliseconds to delay after an initial bus reset.
        The bus settle delay following all error recovery actions is
        dictated by the SCSI layer and is not affected by this value.
 
-       Default: 15000 (15 seconds)
+       Default: 5000 (5 seconds)
 
 config AIC79XX_BUILD_FIRMWARE
        bool "Build Adapter Firmware with Kernel Build"
index 2cfdbef447db6ba7c4f7b774fcce47fe5f53e409..1d11f7e77564e9d83379532bc892d06da4b7a4e4 100644 (file)
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#108 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#109 $
  *
  * $FreeBSD$
  */
@@ -222,6 +222,7 @@ typedef enum {
 typedef enum {
        AHD_FENONE              = 0x00000,
        AHD_WIDE                = 0x00001,/* Wide Channel */
+       AHD_AIC79XXB_SLOWCRC    = 0x00002,/* SLOWCRC bit should be set */
        AHD_MULTI_FUNC          = 0x00100,/* Multi-Function/Channel Device */
        AHD_TARGETMODE          = 0x01000,/* Has tested target mode support */
        AHD_MULTIROLE           = 0x02000,/* Space for two roles at a time */
index 3a3204703b155f374a7cf99cb86dcb2b028f8c05..be14e2ecb8f796b6bdaebe3c4926481160a238bd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Aic79xx register and scratch ram definitions.
  *
- * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 1994-2001, 2004 Justin T. Gibbs.
  * Copyright (c) 2000-2002 Adaptec Inc.
  * All rights reserved.
  *
@@ -39,7 +39,7 @@
  *
  * $FreeBSD$
  */
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#76 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#77 $"
 
 /*
  * This file is processed by the aic7xxx_asm utility for use in assembling
@@ -3715,8 +3715,9 @@ scratch_ram {
 
        SEQ_FLAGS2 {
                size            1
-               field   TARGET_MSG_PENDING        0x02
-               field   SELECTOUT_QFROZEN         0x04
+               field   PENDING_MK_MESSAGE      0x01
+               field   TARGET_MSG_PENDING      0x02
+               field   SELECTOUT_QFROZEN       0x04
        }
 
        ALLOCFIFO_SCBPTR {
@@ -3777,6 +3778,26 @@ scratch_ram {
        CMDSIZE_TABLE {
                size            8
        }
+       /*
+        * When an SCB with the MK_MESSAGE flag is
+        * queued to the controller, it cannot enter
+        * the waiting for selection list until the
+        * selections for any previously queued
+        * commands to that target complete.  During
+        * the wait, the MK_MESSAGE SCB is queued
+        * here.
+        */
+       MK_MESSAGE_SCB {
+               size            2
+       }
+       /*
+        * Saved SCSIID of MK_MESSAGE_SCB to avoid
+        * an extra SCBPTR operation when deciding
+        * if the MK_MESSAGE_SCB can be run.
+        */
+       MK_MESSAGE_SCSIID {
+               size            1
+       }
 }
 
 /************************* Hardware SCB Definition ****************************/
index bef1f9d369b6b90779d13f3ee54a53c7a105bb3a..58bc17591b54ce56082d67aa937f9a8f7e51a0fe 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Adaptec U320 device driver firmware for Linux and FreeBSD.
  *
- * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 1994-2001, 2004 Justin T. Gibbs.
  * Copyright (c) 2000-2002 Adaptec Inc.
  * All rights reserved.
  *
@@ -40,7 +40,7 @@
  * $FreeBSD$
  */
 
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#119 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#120 $"
 PATCH_ARG_LIST = "struct ahd_softc *ahd"
 PREFIX = "ahd_"
 
@@ -110,10 +110,8 @@ check_waiting_list:
         * one last time.
         */
        test    SSTAT0, SELDO jnz select_out;
-END_CRITICAL;
        call    start_selection;
 idle_loop_checkbus:
-BEGIN_CRITICAL;
        test    SSTAT0, SELDO jnz select_out;
 END_CRITICAL;
        test    SSTAT0, SELDI jnz select_in;
@@ -294,7 +292,6 @@ fetch_new_scb_inprog:
        test    CCSCBCTL, ARRDONE jz return;
 fetch_new_scb_done:
        and     CCSCBCTL, ~(CCARREN|CCSCBEN);
-       bmov    REG0, SCBPTR, 2;
        clr     A;
        add     CMDS_PENDING, 1;
        adc     CMDS_PENDING[1], A;
@@ -316,43 +313,117 @@ fetch_new_scb_done:
        clr     SCB_FIFO_USE_COUNT;
        /* Update the next SCB address to download. */
        bmov    NEXT_QUEUED_SCB_ADDR, SCB_NEXT_SCB_BUSADDR, 4;
+       /*
+        * NULL out the SCB links since these fields
+        * occupy the same location as SCB_NEXT_SCB_BUSADDR.
+        */
        mvi     SCB_NEXT[1], SCB_LIST_NULL;
        mvi     SCB_NEXT2[1], SCB_LIST_NULL;
        /* Increment our position in the QINFIFO. */
        mov     NONE, SNSCB_QOFF;
+
        /*
-        * SCBs that want to send messages are always
-        * queued independently.  This ensures that they
-        * are at the head of the SCB list to select out
-        * to a target and we will see the MK_MESSAGE flag.
+        * Save SCBID of this SCB in REG0 since
+        * SCBPTR will be clobbered during target
+        * list updates.  We also record the SCB's
+        * flags so that we can refer to them even
+        * after SCBPTR has been changed.
+        */
+       bmov    REG0, SCBPTR, 2;
+       mov     A, SCB_CONTROL;
+
+       /*
+        * Find the tail SCB of the execution queue
+        * for this target.
         */
-       test    SCB_CONTROL, MK_MESSAGE jnz first_new_target_scb;
        shr     SINDEX, 3, SCB_SCSIID;
        and     SINDEX, ~0x1;
        mvi     SINDEX[1], (WAITING_SCB_TAILS >> 8);
        bmov    DINDEX, SINDEX, 2;
        bmov    SCBPTR, SINDIR, 2;
+
+       /*
+        * Update the tail to point to the new SCB.
+        */
        bmov    DINDIR, REG0, 2;
+
+       /*
+        * If the queue was empty, queue this SCB as
+        * the first for this target.
+        */
        cmp     SCBPTR[1], SCB_LIST_NULL je first_new_target_scb;
+
+       /*
+        * SCBs that want to send messages must always be
+        * at the head of their per-target queue so that
+        * ATN can be asserted even if the current
+        * negotiation agreement is packetized.  If the
+        * target queue is empty, the SCB can be queued
+        * immediately.  If the queue is not empty, we must
+        * wait for it to empty before entering this SCB
+        * into the waiting for selection queue.  Otherwise
+        * our batching and round-robin selection scheme 
+        * could allow commands to be queued out of order.
+        * To simplify the implementation, we stop pulling
+        * new commands from the host until the MK_MESSAGE
+        * SCB can be queued to the waiting for selection
+        * list.
+        */
+       test    A, MK_MESSAGE jz batch_scb; 
+
+       /*
+        * If the last SCB is also a MK_MESSAGE SCB, then
+        * order is preserved even if we batch.
+        */
+       test    SCB_CONTROL, MK_MESSAGE jz batch_scb; 
+
+       /*
+        * Defer this SCB and stop fetching new SCBs until
+        * it can be queued.  Since the SCB_SCSIID of the
+        * tail SCB must be the same as that of the newly
+        * queued SCB, there is no need to restore the SCBID
+        * here.
+        */
+       or      SEQ_FLAGS2, PENDING_MK_MESSAGE;
+       bmov    MK_MESSAGE_SCB, REG0, 2;
+       mov     MK_MESSAGE_SCSIID, SCB_SCSIID ret;
+
+batch_scb:
+       /*
+        * Otherwise just update the previous tail SCB to
+        * point to the new tail.
+        */
        bmov    SCB_NEXT, REG0, 2 ret;
+
 first_new_target_scb:
+       /*
+        * Append SCB to the tail of the waiting for
+        * selection list.
+        */
        cmp     WAITING_TID_HEAD[1], SCB_LIST_NULL je first_new_scb;
        bmov    SCBPTR, WAITING_TID_TAIL, 2;
        bmov    SCB_NEXT2, REG0, 2;
        bmov    WAITING_TID_TAIL, REG0, 2 ret;
 first_new_scb:
+       /*
+        * Whole list is empty, so the head of
+        * the list must be initialized too.
+        */
        bmov    WAITING_TID_HEAD, REG0, 2;
        bmov    WAITING_TID_TAIL, REG0, 2 ret;
 END_CRITICAL;
 
 scbdma_idle:
        /*
-        * Give precedence to downloading new SCBs to execute
-        * unless select-outs are currently frozen.
+        * Don't bother downloading new SCBs to execute
+        * if select-outs are currently frozen or we have
+        * a MK_MESSAGE SCB waiting to enter the queue.
         */
-       test    SEQ_FLAGS2, SELECTOUT_QFROZEN jnz . + 2;
+       test    SEQ_FLAGS2, SELECTOUT_QFROZEN|PENDING_MK_MESSAGE
+               jnz scbdma_no_new_scbs;
 BEGIN_CRITICAL;
        test    QOFF_CTLSTA, NEW_SCB_AVAIL jnz fetch_new_scb;
+scbdma_no_new_scbs:
        cmp     COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne dma_complete_scb;
        cmp     COMPLETE_SCB_HEAD[1], SCB_LIST_NULL je return;
        /* FALLTHROUGH */
@@ -671,27 +742,41 @@ curscb_ww_done:
        }
 
        /*
-        * Requeue any SCBs not sent, to the tail of the waiting Q.
+        * The whole list made it.  Clear our tail pointer to indicate
+        * that the per-target selection queue is now empty.
         */
-       cmp     SCB_NEXT[1], SCB_LIST_NULL je select_out_list_done;
+       cmp     SCB_NEXT[1], SCB_LIST_NULL je select_out_clear_tail;
 
        /*
+        * Requeue any SCBs not sent, to the tail of the waiting Q.
         * We know that neither the per-TID list nor the list of
-        * TIDs is empty.  Use this knowledge to our advantage.
+        * TIDs is empty.  Use this knowledge to our advantage and
+        * queue the remainder to the tail of the global execution
+        * queue.
         */
        bmov    REG0, SCB_NEXT, 2;
+select_out_queue_remainder:
        bmov    SCBPTR, WAITING_TID_TAIL, 2;
        bmov    SCB_NEXT2, REG0, 2;
        bmov    WAITING_TID_TAIL, REG0, 2;
        jmp     select_out_inc_tid_q;
 
-select_out_list_done:
+select_out_clear_tail:
+       /*
+        * Queue any pending MK_MESSAGE SCB for this target now
+        * that the queue is empty.
+        */
+       test    SEQ_FLAGS2, PENDING_MK_MESSAGE jz select_out_no_mk_message_scb;
+       mov     A, MK_MESSAGE_SCSIID;
+       cmp     SCB_SCSIID, A jne select_out_no_mk_message_scb;
+       and     SEQ_FLAGS2, ~PENDING_MK_MESSAGE;
+       bmov    REG0, MK_MESSAGE_SCB, 2;
+       jmp select_out_queue_remainder;
+
+select_out_no_mk_message_scb:
        /*
-        * The whole list made it.  Just clear our TID's tail pointer
-        * unless we were queued independently due to our need to
-        * send a message.
+        * Clear this target's execution tail and increment the queue.
         */
-       test    SCB_CONTROL, MK_MESSAGE jnz select_out_inc_tid_q;
        shr     DINDEX, 3, SCB_SCSIID;
        or      DINDEX, 1;      /* Want only the second byte */
        mvi     DINDEX[1], ((WAITING_SCB_TAILS) >> 8);
@@ -703,8 +788,8 @@ select_out_inc_tid_q:
        mvi     WAITING_TID_TAIL[1], SCB_LIST_NULL;
        bmov    SCBPTR, CURRSCB, 2;
        mvi     CLRSINT0, CLRSELDO;
-       test    LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_phase;
-       test    LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_phase;
+       test    LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_mode_cleared;
+       test    LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_mode_cleared;
 
        /*
         * If this is a packetized connection, return to our
@@ -2127,6 +2212,18 @@ SET_DST_MODE     M_DFF0;
        mvi     DFFSXFRCTL, CLRCHN;
 unexpected_nonpkt_mode_cleared:
        mvi     CLRSINT2, CLRNONPACKREQ;
+       if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) {
+               /*
+                * Test to ensure that the bus has not
+                * already gone free prior to clearing
+                * any stale busfree status.  This avoids
+                * a window whereby a busfree just after
+                * a selection could be missed.
+                */
+               test    SCSISIGI, BSYI jz . + 2;
+               mvi     CLRSINT1,CLRBUSFREE;
+               or      SIMODE1, ENBUSFREE;
+       }
        test    SCSIPHASE, ~(MSG_IN_PHASE|MSG_OUT_PHASE) jnz illegal_phase;
        SET_SEQINTCODE(ENTERING_NONPACK)
        jmp     ITloop;
index db8f5ce99ee3f815a018a1264bb3c50299a7ce99..342f77966a5ba6d066f2ba3eb96c3ba9801845ef 100644 (file)
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#247 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#250 $
  */
 
 #ifdef __linux__
@@ -197,7 +197,8 @@ static int          ahd_search_scb_list(struct ahd_softc *ahd, int target,
                                            char channel, int lun, u_int tag,
                                            role_t role, uint32_t status,
                                            ahd_search_action action,
-                                           u_int *list_head, u_int tid);
+                                           u_int *list_head, u_int *list_tail,
+                                           u_int tid);
 static void            ahd_stitch_tid_list(struct ahd_softc *ahd,
                                            u_int tid_prev, u_int tid_cur,
                                            u_int tid_next);
@@ -1660,7 +1661,8 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                 * so just clear the error.
                 */
                ahd_outb(ahd, CLRLQIINT1, CLRLQICRCI_NLQ);
-       } else if ((status & BUSFREE) != 0) {
+       } else if ((status & BUSFREE) != 0
+               || (lqistat1 & LQOBUSFREE) != 0) {
                u_int lqostat1;
                int   restart;
                int   clear_fifo;
@@ -2025,10 +2027,6 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
                u_int waiting_t;
                u_int next;
 
-               if ((busfreetime & BUSFREE_LQO) == 0)
-                       printf("%s: Warning, BUSFREE time is 0x%x.  "
-                              "Expected BUSFREE_LQO.\n",
-                              ahd_name(ahd), busfreetime);
                /*
                 * The LQO manager detected an unexpected busfree
                 * either:
@@ -2251,8 +2249,14 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
                        struct ahd_tmode_tstate *tstate;
 
                        /*
-                        * PPR Rejected.  Try non-ppr negotiation
-                        * and retry command.
+                        * PPR Rejected.
+                        *
+                        * If the previous negotiation was packetized,
+                        * this could be because the device has been
+                        * reset without our knowledge.  Force our
+                        * current negotiation to async and retry the
+                        * negotiation.  Otherwise retry the command
+                        * with non-ppr negotiation.
                         */
 #ifdef AHD_DEBUG
                        if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
@@ -2261,11 +2265,34 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
                        tinfo = ahd_fetch_transinfo(ahd, devinfo.channel,
                                                    devinfo.our_scsiid,
                                                    devinfo.target, &tstate);
-                       tinfo->curr.transport_version = 2;
-                       tinfo->goal.transport_version = 2;
-                       tinfo->goal.ppr_options = 0;
-                       ahd_qinfifo_requeue_tail(ahd, scb);
-                       printerror = 0;
+                       if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ)!=0) {
+                               ahd_set_width(ahd, &devinfo,
+                                             MSG_EXT_WDTR_BUS_8_BIT,
+                                             AHD_TRANS_CUR,
+                                             /*paused*/TRUE);
+                               ahd_set_syncrate(ahd, &devinfo,
+                                               /*period*/0, /*offset*/0,
+                                               /*ppr_options*/0,
+                                               AHD_TRANS_CUR,
+                                               /*paused*/TRUE);
+                               /*
+                                * The expect PPR busfree handler below
+                                * will effect the retry and necessary
+                                * abort.
+                                */
+                       } else {
+                               tinfo->curr.transport_version = 2;
+                               tinfo->goal.transport_version = 2;
+                               tinfo->goal.ppr_options = 0;
+                               /*
+                                * Remove any SCBs in the waiting for selection
+                                * queue that may also be for this target so
+                                * that command ordering is preserved.
+                                */
+                               ahd_freeze_devq(ahd, scb);
+                               ahd_qinfifo_requeue_tail(ahd, scb);
+                               printerror = 0;
+                       }
                } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE)
                        && ppr_busfree == 0) {
                        /*
@@ -2280,6 +2307,12 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
                                      MSG_EXT_WDTR_BUS_8_BIT,
                                      AHD_TRANS_CUR|AHD_TRANS_GOAL,
                                      /*paused*/TRUE);
+                       /*
+                        * Remove any SCBs in the waiting for selection
+                        * queue that may also be for this target so that
+                        * command ordering is preserved.
+                        */
+                       ahd_freeze_devq(ahd, scb);
                        ahd_qinfifo_requeue_tail(ahd, scb);
                        printerror = 0;
                } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE)
@@ -2297,6 +2330,12 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
                                        /*ppr_options*/0,
                                        AHD_TRANS_CUR|AHD_TRANS_GOAL,
                                        /*paused*/TRUE);
+                       /*
+                        * Remove any SCBs in the waiting for selection
+                        * queue that may also be for this target so that
+                        * command ordering is preserved.
+                        */
+                       ahd_freeze_devq(ahd, scb);
                        ahd_qinfifo_requeue_tail(ahd, scb);
                        printerror = 0;
                } else if ((ahd->msg_flags & MSG_FLAG_EXPECT_IDE_BUSFREE) != 0
@@ -2369,14 +2408,14 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
                         */
                        printf("%s: ", ahd_name(ahd));
                }
-               if (lastphase != P_BUSFREE)
-                       ahd_force_renegotiation(ahd, &devinfo);
                printf("Unexpected busfree %s, %d SCBs aborted, "
                       "PRGMCNT == 0x%x\n",
                       ahd_lookup_phase_entry(lastphase)->phasemsg,
                       aborted,
                       ahd_inw(ahd, PRGMCNT));
                ahd_dump_card_state(ahd);
+               if (lastphase != P_BUSFREE)
+                       ahd_force_renegotiation(ahd, &devinfo);
        }
        /* Always restart the sequencer. */
        return (1);
@@ -3292,6 +3331,15 @@ ahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
        if (tinfo->width == MSG_EXT_WDTR_BUS_16_BIT)
                con_opts |= WIDEXFER;
 
+       /*
+        * Slow down our CRC interval to be
+        * compatible with packetized U320 devices
+        * that can't handle a CRC at full speed
+        */
+       if (ahd->features & AHD_AIC79XXB_SLOWCRC) {
+               con_opts |= ENSLOWCRC;
+       }
+
        /*
         * During packetized transfers, the target will
         * give us the oportunity to send command packets
@@ -3315,7 +3363,6 @@ ahd_update_pending_scbs(struct ahd_softc *ahd)
 {
        struct          scb *pending_scb;
        int             pending_scb_count;
-       u_int           scb_tag;
        int             paused;
        u_int           saved_scbptr;
        ahd_mode_state  saved_modes;
@@ -3333,7 +3380,6 @@ ahd_update_pending_scbs(struct ahd_softc *ahd)
        pending_scb_count = 0;
        LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) {
                struct ahd_devinfo devinfo;
-               struct hardware_scb *pending_hscb;
                struct ahd_initiator_tinfo *tinfo;
                struct ahd_tmode_tstate *tstate;
 
@@ -3341,11 +3387,10 @@ ahd_update_pending_scbs(struct ahd_softc *ahd)
                tinfo = ahd_fetch_transinfo(ahd, devinfo.channel,
                                            devinfo.our_scsiid,
                                            devinfo.target, &tstate);
-               pending_hscb = pending_scb->hscb;
                if ((tstate->auto_negotiate & devinfo.target_mask) == 0
                 && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) {
                        pending_scb->flags &= ~SCB_AUTO_NEGOTIATE;
-                       pending_hscb->control &= ~MK_MESSAGE;
+                       pending_scb->hscb->control &= ~MK_MESSAGE;
                }
                ahd_sync_scb(ahd, pending_scb,
                             BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
@@ -3377,18 +3422,15 @@ ahd_update_pending_scbs(struct ahd_softc *ahd)
                ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
        saved_scbptr = ahd_get_scbptr(ahd);
        /* Ensure that the hscbs down on the card match the new information */
-       for (scb_tag = 0; scb_tag < ahd->scb_data.maxhscbs; scb_tag++) {
-               struct  hardware_scb *pending_hscb;
+       LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) {
+               u_int   scb_tag;
                u_int   control;
 
-               pending_scb = ahd_lookup_scb(ahd, scb_tag);
-               if (pending_scb == NULL)
-                       continue;
+               scb_tag = SCB_GET_TAG(pending_scb);
                ahd_set_scbptr(ahd, scb_tag);
-               pending_hscb = pending_scb->hscb;
                control = ahd_inb_scbram(ahd, SCB_CONTROL);
                control &= ~MK_MESSAGE;
-               control |= pending_hscb->control & MK_MESSAGE;
+               control |= pending_scb->hscb->control & MK_MESSAGE;
                ahd_outb(ahd, SCB_CONTROL, control);
        }
        ahd_set_scbptr(ahd, saved_scbptr);
@@ -6500,13 +6542,14 @@ ahd_chip_init(struct ahd_softc *ahd)
                              | ENLQIOVERI_LQ|ENLQIOVERI_NLQ);
        ahd_outb(ahd, LQOMODE0, ENLQOATNLQ|ENLQOATNPKT|ENLQOTCRC);
        /*
-        * An interrupt from LQOBUSFREE is made redundant by the
-        * BUSFREE interrupt.  We choose to have the sequencer catch
-        * LQOPHCHGINPKT errors manually for the command phase at the
-        * start of a packetized selection case.
-       ahd_outb(ahd, LQOMODE1, ENLQOBUSFREE|ENLQOPHACHGINPKT);
+        * We choose to have the sequencer catch LQOPHCHGINPKT errors
+        * manually for the command phase at the start of a packetized
+        * selection case.  ENLQOBUSFREE should be made redundant by
+        * the BUSFREE interrupt, but it seems that some LQOBUSFREE
+        * events fail to assert the BUSFREE interrupt so we must
+        * also enable LQOBUSFREE interrupts.
         */
-       ahd_outb(ahd, LQOMODE1, 0);
+       ahd_outb(ahd, LQOMODE1, ENLQOBUSFREE);
 
        /*
         * Setup sequencer interrupt handlers.
@@ -6617,6 +6660,8 @@ ahd_chip_init(struct ahd_softc *ahd)
        /* We don't have any waiting selections */
        ahd_outw(ahd, WAITING_TID_HEAD, SCB_LIST_NULL);
        ahd_outw(ahd, WAITING_TID_TAIL, SCB_LIST_NULL);
+       ahd_outw(ahd, MK_MESSAGE_SCB, SCB_LIST_NULL);
+       ahd_outw(ahd, MK_MESSAGE_SCSIID, 0xFF);
        for (i = 0; i < AHD_NUM_TARGETS; i++)
                ahd_outw(ahd, WAITING_SCB_TAILS + (2 * i), SCB_LIST_NULL);
 
@@ -6704,6 +6749,18 @@ ahd_chip_init(struct ahd_softc *ahd)
 
        ahd_loadseq(ahd);
        ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+
+       if (ahd->features & AHD_AIC79XXB_SLOWCRC) {
+               u_int negodat3 = ahd_inb(ahd, NEGCONOPTS);
+
+               negodat3 |= ENSLOWCRC;
+               ahd_outb(ahd, NEGCONOPTS, negodat3);
+               negodat3 = ahd_inb(ahd, NEGCONOPTS);
+               if (!(negodat3 & ENSLOWCRC))
+                       printf("aic79xx: failed to set the SLOWCRC bit\n");
+               else
+                       printf("aic79xx: SLOWCRC bit set\n");
+       }
 }
 
 /*
@@ -7260,12 +7317,28 @@ ahd_reset_cmds_pending(struct ahd_softc *ahd)
        ahd->flags &= ~AHD_UPDATE_PEND_CMDS;
 }
 
+void
+ahd_done_with_status(struct ahd_softc *ahd, struct scb *scb, uint32_t status)
+{
+       cam_status ostat;
+       cam_status cstat;
+
+       ostat = ahd_get_transaction_status(scb);
+       if (ostat == CAM_REQ_INPROG)
+               ahd_set_transaction_status(scb, status);
+       cstat = ahd_get_transaction_status(scb);
+       if (cstat != CAM_REQ_CMP)
+               ahd_freeze_scb(scb);
+       ahd_done(ahd, scb);
+}
+
 int
 ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
                   int lun, u_int tag, role_t role, uint32_t status,
                   ahd_search_action action)
 {
        struct scb      *scb;
+       struct scb      *mk_msg_scb;
        struct scb      *prev_scb;
        ahd_mode_state   saved_modes;
        u_int            qinstart;
@@ -7274,6 +7347,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
        u_int            tid_next;
        u_int            tid_prev;
        u_int            scbid;
+       u_int            seq_flags2;
        u_int            savedscbptr;
        uint32_t         busaddr;
        int              found;
@@ -7329,23 +7403,10 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
                        found++;
                        switch (action) {
                        case SEARCH_COMPLETE:
-                       {
-                               cam_status ostat;
-                               cam_status cstat;
-
-                               ostat = ahd_get_transaction_status(scb);
-                               if (ostat == CAM_REQ_INPROG)
-                                       ahd_set_transaction_status(scb,
-                                                                  status);
-                               cstat = ahd_get_transaction_status(scb);
-                               if (cstat != CAM_REQ_CMP)
-                                       ahd_freeze_scb(scb);
                                if ((scb->flags & SCB_ACTIVE) == 0)
                                        printf("Inactive SCB in qinfifo\n");
-                               ahd_done(ahd, scb);
-
+                               ahd_done_with_status(ahd, scb, status);
                                /* FALLTHROUGH */
-                       }
                        case SEARCH_REMOVE:
                                break;
                        case SEARCH_PRINT:
@@ -7375,21 +7436,24 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
         * looking for matches.
         */
        ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+       seq_flags2 = ahd_inb(ahd, SEQ_FLAGS2);
+       if ((seq_flags2 & PENDING_MK_MESSAGE) != 0) {
+               scbid = ahd_inw(ahd, MK_MESSAGE_SCB);
+               mk_msg_scb = ahd_lookup_scb(ahd, scbid);
+       } else
+               mk_msg_scb = NULL;
        savedscbptr = ahd_get_scbptr(ahd);
        tid_next = ahd_inw(ahd, WAITING_TID_HEAD);
        tid_prev = SCB_LIST_NULL;
        targets = 0;
        for (scbid = tid_next; !SCBID_IS_NULL(scbid); scbid = tid_next) {
                u_int tid_head;
+               u_int tid_tail;
 
-               /*
-                * We limit based on the number of SCBs since
-                * MK_MESSAGE SCBs are not in the per-tid lists.
-                */
                targets++;
-               if (targets > AHD_SCB_MAX) {
+               if (targets > AHD_NUM_TARGETS)
                        panic("TID LIST LOOP");
-               }
+
                if (scbid >= ahd->scb_data.numscbs) {
                        printf("%s: Waiting TID List inconsistency. "
                               "SCB index == 0x%x, yet numscbs == 0x%x.",
@@ -7419,8 +7483,71 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
                tid_head = scbid;
                found += ahd_search_scb_list(ahd, target, channel,
                                             lun, tag, role, status,
-                                            action, &tid_head,
+                                            action, &tid_head, &tid_tail,
                                             SCB_GET_TARGET(ahd, scb));
+               /*
+                * Check any MK_MESSAGE SCB that is still waiting to
+                * enter this target's waiting for selection queue.
+                */
+               if (mk_msg_scb != NULL
+                && ahd_match_scb(ahd, mk_msg_scb, target, channel,
+                                 lun, tag, role)) {
+
+                       /*
+                        * We found an scb that needs to be acted on.
+                        */
+                       found++;
+                       switch (action) {
+                       case SEARCH_COMPLETE:
+                               if ((mk_msg_scb->flags & SCB_ACTIVE) == 0)
+                                       printf("Inactive SCB pending MK_MSG\n");
+                               ahd_done_with_status(ahd, mk_msg_scb, status);
+                               /* FALLTHROUGH */
+                       case SEARCH_REMOVE:
+                       {
+                               u_int tail_offset;
+
+                               printf("Removing MK_MSG scb\n");
+
+                               /*
+                                * Reset our tail to the tail of the
+                                * main per-target list.
+                                */
+                               tail_offset = WAITING_SCB_TAILS
+                                   + (2 * SCB_GET_TARGET(ahd, mk_msg_scb));
+                               ahd_outw(ahd, tail_offset, tid_tail);
+
+                               seq_flags2 &= ~PENDING_MK_MESSAGE;
+                               ahd_outb(ahd, SEQ_FLAGS2, seq_flags2);
+                               ahd_outw(ahd, CMDS_PENDING,
+                                        ahd_inw(ahd, CMDS_PENDING)-1);
+                               mk_msg_scb = NULL;
+                               break;
+                       }
+                       case SEARCH_PRINT:
+                               printf(" 0x%x", SCB_GET_TAG(scb));
+                               /* FALLTHROUGH */
+                       case SEARCH_COUNT:
+                               break;
+                       }
+               }
+
+               if (mk_msg_scb != NULL
+                && SCBID_IS_NULL(tid_head)
+                && ahd_match_scb(ahd, scb, target, channel, CAM_LUN_WILDCARD,
+                                 SCB_LIST_NULL, ROLE_UNKNOWN)) {
+
+                       /*
+                        * When removing the last SCB for a target
+                        * queue with a pending MK_MESSAGE scb, we
+                        * must queue the MK_MESSAGE scb.
+                        */
+                       printf("Queueing mk_msg_scb\n");
+                       tid_head = ahd_inw(ahd, MK_MESSAGE_SCB);
+                       seq_flags2 &= ~PENDING_MK_MESSAGE;
+                       ahd_outb(ahd, SEQ_FLAGS2, seq_flags2);
+                       mk_msg_scb = NULL;
+               }
                if (tid_head != scbid)
                        ahd_stitch_tid_list(ahd, tid_prev, tid_head, tid_next);
                if (!SCBID_IS_NULL(tid_head))
@@ -7428,6 +7555,8 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
                if (action == SEARCH_PRINT)
                        printf(")\n");
        }
+
+       /* Restore saved state. */
        ahd_set_scbptr(ahd, savedscbptr);
        ahd_restore_modes(ahd, saved_modes);
        return (found);
@@ -7436,7 +7565,8 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
 static int
 ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
                    int lun, u_int tag, role_t role, uint32_t status,
-                   ahd_search_action action, u_int *list_head, u_int tid)
+                   ahd_search_action action, u_int *list_head, 
+                   u_int *list_tail, u_int tid)
 {
        struct  scb *scb;
        u_int   scbid;
@@ -7448,6 +7578,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
        found = 0;
        prev = SCB_LIST_NULL;
        next = *list_head;
+       *list_tail = SCB_LIST_NULL;
        for (scbid = next; !SCBID_IS_NULL(scbid); scbid = next) {
                if (scbid >= ahd->scb_data.numscbs) {
                        printf("%s:SCB List inconsistency. "
@@ -7463,6 +7594,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
                        panic("Waiting List traversal\n");
                }
                ahd_set_scbptr(ahd, scbid);
+               *list_tail = scbid;
                next = ahd_inw_scbram(ahd, SCB_NEXT);
                if (ahd_match_scb(ahd, scb, target, channel,
                                  lun, SCB_LIST_NULL, role) == 0) {
@@ -7472,24 +7604,14 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
                found++;
                switch (action) {
                case SEARCH_COMPLETE:
-               {
-                       cam_status ostat;
-                       cam_status cstat;
-
-                       ostat = ahd_get_transaction_status(scb);
-                       if (ostat == CAM_REQ_INPROG)
-                               ahd_set_transaction_status(scb, status);
-                       cstat = ahd_get_transaction_status(scb);
-                       if (cstat != CAM_REQ_CMP)
-                               ahd_freeze_scb(scb);
                        if ((scb->flags & SCB_ACTIVE) == 0)
                                printf("Inactive SCB in Waiting List\n");
-                       ahd_done(ahd, scb);
+                       ahd_done_with_status(ahd, scb, status);
                        /* FALLTHROUGH */
-               }
                case SEARCH_REMOVE:
                        ahd_rem_wscb(ahd, scbid, prev, next, tid);
-                       if (prev == SCB_LIST_NULL)
+                       *list_tail = prev;
+                       if (SCBID_IS_NULL(prev))
                                *list_head = next;
                        break;
                case SEARCH_PRINT:
@@ -7558,14 +7680,17 @@ ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,
        }
 
        /*
-        * SCBs that had MK_MESSAGE set in them will not
-        * be queued to the per-target lists, so don't
-        * blindly clear the tail pointer.
+        * SCBs that have MK_MESSAGE set in them may
+        * cause the tail pointer to be updated without
+        * setting the next pointer of the previous tail.
+        * Only clear the tail if the removed SCB was
+        * the tail.
         */
        tail_offset = WAITING_SCB_TAILS + (2 * tid);
        if (SCBID_IS_NULL(next)
         && ahd_inw(ahd, tail_offset) == scbid)
                ahd_outw(ahd, tail_offset, prev);
+
        ahd_add_scb_to_free_list(ahd, scbid);
        return (next);
 }
@@ -8148,11 +8273,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
                ahd_setup_data_scb(ahd, scb);
                scb->flags |= SCB_SENSE;
                ahd_queue_scb(ahd, scb);
-               /*
-                * Ensure we have enough time to actually
-                * retrieve the sense.
-                */
-               ahd_scb_timer_reset(scb, 5 * 1000000);
                break;
        }
        case SCSI_STATUS_OK:
@@ -8793,6 +8913,9 @@ ahd_dump_card_state(struct ahd_softc *ahd)
         * Mode independent registers.
         */
        cur_col = 0;
+       ahd_intstat_print(ahd_inb(ahd, INTSTAT), &cur_col, 50);
+       ahd_seloid_print(ahd_inb(ahd, SELOID), &cur_col, 50);
+       ahd_selid_print(ahd_inb(ahd, SELID), &cur_col, 50);
        ahd_hs_mailbox_print(ahd_inb(ahd, LOCAL_HS_MAILBOX), &cur_col, 50);
        ahd_intctl_print(ahd_inb(ahd, INTCTL), &cur_col, 50);
        ahd_seqintstat_print(ahd_inb(ahd, SEQINTSTAT), &cur_col, 50);
@@ -8808,6 +8931,12 @@ ahd_dump_card_state(struct ahd_softc *ahd)
        ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &cur_col, 50);
        ahd_seq_flags_print(ahd_inb(ahd, SEQ_FLAGS), &cur_col, 50);
        ahd_seq_flags2_print(ahd_inb(ahd, SEQ_FLAGS2), &cur_col, 50);
+       ahd_qfreeze_count_print(ahd_inw(ahd, QFREEZE_COUNT), &cur_col, 50);
+       ahd_kernel_qfreeze_count_print(ahd_inw(ahd, KERNEL_QFREEZE_COUNT),
+                                      &cur_col, 50);
+       ahd_mk_message_scb_print(ahd_inw(ahd, MK_MESSAGE_SCB), &cur_col, 50);
+       ahd_mk_message_scsiid_print(ahd_inb(ahd, MK_MESSAGE_SCSIID),
+                                   &cur_col, 50);
        ahd_sstat0_print(ahd_inb(ahd, SSTAT0), &cur_col, 50);
        ahd_sstat1_print(ahd_inb(ahd, SSTAT1), &cur_col, 50);
        ahd_sstat2_print(ahd_inb(ahd, SSTAT2), &cur_col, 50);
@@ -8915,7 +9044,7 @@ ahd_dump_card_state(struct ahd_softc *ahd)
 
                ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i);
                fifo_scbptr = ahd_get_scbptr(ahd);
-               printf("\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n",
+               printf("\n\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n",
                       ahd_name(ahd), i,
                       (dffstat & (FIFO0FREE << i)) ? "Free" : "Active",
                       ahd_inw(ahd, LONGJMP_ADDR), fifo_scbptr);
@@ -8970,6 +9099,9 @@ ahd_dump_card_state(struct ahd_softc *ahd)
        printf("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n",
               ahd_name(ahd), ahd_inb(ahd, OS_SPACE_CNT),
               ahd_inb(ahd, MAXCMDCNT));
+       printf("%s: SAVED_SCSIID = 0x%x SAVED_LUN = 0x%x\n",
+              ahd_name(ahd), ahd_inb(ahd, SAVED_SCSIID),
+              ahd_inb(ahd, SAVED_LUN));
        ahd_simode0_print(ahd_inb(ahd, SIMODE0), &cur_col, 50);
        printf("\n");
        ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
index 91c4f7f484b1271d37cf7b7334998aa30cff8344..8ad3ce945b9e5f36b20953af23ff1717d64403a4 100644 (file)
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#58 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#59 $
  *
  * $FreeBSD$
  */
@@ -804,9 +804,10 @@ ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
                uint64_t host_dataptr;
 
                host_dataptr = ahd_le64toh(scb->hscb->dataptr);
-               printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
+               printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
                       ahd_name(ahd),
-                      SCB_GET_TAG(scb), ahd_le32toh(scb->hscb->hscb_busaddr),
+                      SCB_GET_TAG(scb), scb->hscb->scsiid,
+                      ahd_le32toh(scb->hscb->hscb_busaddr),
                       (u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
                       (u_int)(host_dataptr & 0xFFFFFFFF),
                       ahd_le32toh(scb->hscb->datacnt));
index 2567e29960bd1697565490d2840a3312f6414ab1..7254ea535a160c81b9b016b4a254a8468ea96028 100644 (file)
@@ -314,6 +314,21 @@ static uint32_t aic79xx_seltime;
  */
 uint32_t aic79xx_periodic_otag;
 
+/* Some storage boxes are using an LSI chip which has a bug making it
+ * impossible to use aic79xx Rev B chip in 320 speeds.  The following
+ * storage boxes have been reported to be buggy:
+ * EonStor 3U 16-Bay: U16U-G3A3
+ * EonStor 2U 12-Bay: U12U-G3A3
+ * SentinelRAID: 2500F R5 / R6
+ * SentinelRAID: 2500F R1
+ * SentinelRAID: 2500F/1500F
+ * SentinelRAID: 150F
+ * 
+ * To get around this LSI bug, you can set your board to 160 mode
+ * or you can enable the SLOWCRC bit.
+ */
+uint32_t aic79xx_slowcrc;
+
 /*
  * Module information and settable options.
  */
@@ -343,6 +358,7 @@ MODULE_PARM_DESC(aic79xx,
 "      amplitude:<int>         Set the signal amplitude (0-7).\n"
 "      seltime:<int>           Selection Timeout:\n"
 "                              (0/256ms,1/128ms,2/64ms,3/32ms)\n"
+"      slowcrc                 Turn on the SLOWCRC bit (Rev B only)\n"          
 "\n"
 "      Sample /etc/modprobe.conf line:\n"
 "              Enable verbose logging\n"
@@ -1003,6 +1019,7 @@ aic79xx_setup(char *s)
                { "slewrate", NULL },
                { "precomp", NULL },
                { "amplitude", NULL },
+               { "slowcrc", &aic79xx_slowcrc },
        };
 
        end = strchr(s, '\0');
@@ -1072,7 +1089,6 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa
                return (ENOMEM);
 
        *((struct ahd_softc **)host->hostdata) = ahd;
-       ahd_lock(ahd, &s);
        ahd->platform_data->host = host;
        host->can_queue = AHD_MAX_QUEUE;
        host->cmd_per_lun = 2;
@@ -1083,7 +1099,9 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa
        host->max_lun = AHD_NUM_LUNS;
        host->max_channel = 0;
        host->sg_tablesize = AHD_NSEG;
+       ahd_lock(ahd, &s);
        ahd_set_unit(ahd, ahd_linux_unit++);
+       ahd_unlock(ahd, &s);
        sprintf(buf, "scsi%d", host->host_no);
        new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
        if (new_name != NULL) {
@@ -1093,7 +1111,6 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa
        host->unique_id = ahd->unit;
        ahd_linux_initialize_scsi_bus(ahd);
        ahd_intr_enable(ahd, TRUE);
-       ahd_unlock(ahd, &s);
 
        host->transportt = ahd_linux_transport_template;
 
@@ -1127,6 +1144,7 @@ ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd)
 {
        u_int target_id;
        u_int numtarg;
+       unsigned long s;
 
        target_id = 0;
        numtarg = 0;
@@ -1139,6 +1157,8 @@ ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd)
        else
                numtarg = (ahd->features & AHD_WIDE) ? 16 : 8;
 
+       ahd_lock(ahd, &s);
+
        /*
         * Force negotiation to async for all targets that
         * will not see an initial bus reset.
@@ -1155,16 +1175,12 @@ ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd)
                ahd_update_neg_request(ahd, &devinfo, tstate,
                                       tinfo, AHD_NEG_ALWAYS);
        }
+       ahd_unlock(ahd, &s);
        /* Give the bus some time to recover */
        if ((ahd->flags & AHD_RESET_BUS_A) != 0) {
                ahd_freeze_simq(ahd);
-               init_timer(&ahd->platform_data->reset_timer);
-               ahd->platform_data->reset_timer.data = (u_long)ahd;
-               ahd->platform_data->reset_timer.expires =
-                   jiffies + (AIC79XX_RESET_DELAY * HZ)/1000;
-               ahd->platform_data->reset_timer.function =
-                   (ahd_linux_callback_t *)ahd_release_simq;
-               add_timer(&ahd->platform_data->reset_timer);
+               msleep(AIC79XX_RESET_DELAY);
+               ahd_release_simq(ahd);
        }
 }
 
@@ -2033,6 +2049,9 @@ ahd_linux_sem_timeout(u_long arg)
 void
 ahd_freeze_simq(struct ahd_softc *ahd)
 {
+       unsigned long s;
+
+       ahd_lock(ahd, &s);
        ahd->platform_data->qfrozen++;
        if (ahd->platform_data->qfrozen == 1) {
                scsi_block_requests(ahd->platform_data->host);
@@ -2040,6 +2059,7 @@ ahd_freeze_simq(struct ahd_softc *ahd)
                                        CAM_LUN_WILDCARD, SCB_LIST_NULL,
                                        ROLE_INITIATOR, CAM_REQUEUE_REQ);
        }
+       ahd_unlock(ahd, &s);
 }
 
 void
@@ -2344,8 +2364,9 @@ done:
                               ahd_name(ahd), dev->active);
                        retval = FAILED;
                }
-       }
-       ahd_unlock(ahd, &flags);
+       } else
+               ahd_unlock(ahd, &flags);
+
        return (retval);
 }
 
index cb74fccc81007130f602eb75dda433a5d890f113..9cb10134510739933510327cdfaeda8db636c199 100644 (file)
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#137 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#166 $
  *
  */
 #ifndef _AIC79XX_LINUX_H_
@@ -228,7 +228,6 @@ typedef struct timer_list ahd_timer_t;
 typedef void ahd_linux_callback_t (u_long);  
 static __inline void ahd_timer_reset(ahd_timer_t *timer, int usec,
                                     ahd_callback_t *func, void *arg);
-static __inline void ahd_scb_timer_reset(struct scb *scb, u_int usec);
 
 static __inline void
 ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
@@ -243,12 +242,6 @@ ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
        add_timer(timer);
 }
 
-static __inline void
-ahd_scb_timer_reset(struct scb *scb, u_int usec)
-{
-       mod_timer(&scb->io_ctx->eh_timeout, jiffies + (usec * HZ)/1000000);
-}
-
 /***************************** SMP support ************************************/
 #include <linux/spinlock.h>
 
@@ -389,7 +382,6 @@ struct ahd_platform_data {
 
        spinlock_t               spin_lock;
        u_int                    qfrozen;
-       struct timer_list        reset_timer;
        struct semaphore         eh_sem;
        struct Scsi_Host        *host;          /* pointer to scsi host */
 #define AHD_LINUX_NOIRQ        ((uint32_t)~0)
index bf360ae021abb0582482d4702e903a9eda4ac7f8..ebbf7e4ff4cc653e6639caa0ccc8ae5c5867f267 100644 (file)
@@ -220,10 +220,10 @@ ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base,
        *base2 = pci_resource_start(ahd->dev_softc, 3);
        if (*base == 0 || *base2 == 0)
                return (ENOMEM);
-       if (request_region(*base, 256, "aic79xx") == 0)
+       if (!request_region(*base, 256, "aic79xx"))
                return (ENOMEM);
-       if (request_region(*base2, 256, "aic79xx") == 0) {
-               release_region(*base2, 256);
+       if (!request_region(*base2, 256, "aic79xx")) {
+               release_region(*base, 256);
                return (ENOMEM);
        }
        return (0);
@@ -237,7 +237,7 @@ ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
        u_long  start;
        u_long  base_page;
        u_long  base_offset;
-       int     error;
+       int     error = 0;
 
        if (aic79xx_allow_memio == 0)
                return (ENOMEM);
@@ -245,16 +245,15 @@ ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
        if ((ahd->bugs & AHD_PCIX_MMAPIO_BUG) != 0)
                return (ENOMEM);
 
-       error = 0;
        start = pci_resource_start(ahd->dev_softc, 1);
        base_page = start & PAGE_MASK;
        base_offset = start - base_page;
        if (start != 0) {
                *bus_addr = start;
-               if (request_mem_region(start, 0x1000, "aic79xx") == 0)
+               if (!request_mem_region(start, 0x1000, "aic79xx"))
                        error = ENOMEM;
-               if (error == 0) {
-                       *maddr = ioremap_nocache(base_page, base_offset + 256);
+               if (!error) {
+                       *maddr = ioremap_nocache(base_page, base_offset + 512);
                        if (*maddr == NULL) {
                                error = ENOMEM;
                                release_mem_region(start, 0x1000);
@@ -344,7 +343,7 @@ ahd_pci_map_int(struct ahd_softc *ahd)
 
        error = request_irq(ahd->dev_softc->irq, ahd_linux_isr,
                            SA_SHIRQ, "aic79xx", ahd);
-       if (error == 0)
+       if (!error)
                ahd->platform_data->irq = ahd->dev_softc->irq;
        
        return (-error);
index 196a6344b03703ec9b96182d747f20d5b50eafbb..757242e522c2cab761b8bddc1eeb821f8d5bd4d6 100644 (file)
@@ -38,7 +38,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#89 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#92 $
  */
 
 #ifdef __linux__
@@ -950,12 +950,19 @@ ahd_aic790X_setup(struct ahd_softc *ahd)
                if ((ahd->flags & AHD_HP_BOARD) == 0)
                        AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVA);
        } else {
+               /* This is revision B and newer. */
+               extern uint32_t aic79xx_slowcrc;
                u_int devconfig1;
 
                ahd->features |= AHD_RTI|AHD_NEW_IOCELL_OPTS
-                             |  AHD_NEW_DFCNTRL_OPTS|AHD_FAST_CDB_DELIVERY;
+                             |  AHD_NEW_DFCNTRL_OPTS|AHD_FAST_CDB_DELIVERY
+                             |  AHD_BUSFREEREV_BUG;
                ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_EARLY_REQ_BUG;
 
+               /* If the user requested the the SLOWCRC bit to be set. */
+               if (aic79xx_slowcrc)
+                       ahd->features |= AHD_AIC79XXB_SLOWCRC;
+
                /*
                 * Some issues have been resolved in the 7901B.
                 */
index 8763b158856b56aef0dd856c55cafe1a89c11c43..2068e00d2c750a09c8b733aff1fa01af385a395e 100644 (file)
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *              from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#119 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#76 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#120 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#77 $
  */
 typedef int (ahd_reg_print_t)(u_int, u_int *, u_int);
 typedef struct ahd_reg_parse_entry {
@@ -2203,6 +2203,20 @@ ahd_reg_print_t ahd_cmdsize_table_print;
     ahd_print_register(NULL, 0, "CMDSIZE_TABLE", 0x158, regvalue, cur_col, wrap)
 #endif
 
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_mk_message_scb_print;
+#else
+#define ahd_mk_message_scb_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MK_MESSAGE_SCB", 0x160, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_mk_message_scsiid_print;
+#else
+#define ahd_mk_message_scsiid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MK_MESSAGE_SCSIID", 0x162, regvalue, cur_col, wrap)
+#endif
+
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_scb_base_print;
 #else
@@ -3638,6 +3652,7 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define        SEQ_FLAGS2                      0x14d
 #define                SELECTOUT_QFROZEN       0x04
 #define                TARGET_MSG_PENDING      0x02
+#define                PENDING_MK_MESSAGE      0x01
 
 #define        ALLOCFIFO_SCBPTR                0x14e
 
@@ -3655,6 +3670,10 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 #define        CMDSIZE_TABLE                   0x158
 
+#define        MK_MESSAGE_SCB                  0x160
+
+#define        MK_MESSAGE_SCSIID               0x162
+
 #define        SCB_BASE                        0x180
 
 #define        SCB_RESIDUAL_DATACNT            0x180
@@ -3800,5 +3819,5 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 
 /* Exported Labels */
-#define        LABEL_seq_isr   0x285
-#define        LABEL_timer_isr 0x281
+#define        LABEL_seq_isr   0x28f
+#define        LABEL_timer_isr 0x28b
index a4137c985376b6eabff30ed6a366356eafc4e87a..db38a61a8cb4f2cf15160f4406a4749fcb716ad9 100644 (file)
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *              from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#118 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#75 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#120 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#77 $
  */
 
 #include "aic79xx_osm.h"
@@ -3382,6 +3382,7 @@ ahd_initiator_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
 }
 
 static ahd_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
+       { "PENDING_MK_MESSAGE", 0x01, 0x01 },
        { "TARGET_MSG_PENDING", 0x02, 0x02 },
        { "SELECTOUT_QFROZEN",  0x04, 0x04 }
 };
@@ -3389,7 +3390,7 @@ static ahd_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
 int
 ahd_seq_flags2_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(SEQ_FLAGS2_parse_table, 2, "SEQ_FLAGS2",
+       return (ahd_print_register(SEQ_FLAGS2_parse_table, 3, "SEQ_FLAGS2",
            0x14d, regvalue, cur_col, wrap));
 }
 
@@ -3449,6 +3450,20 @@ ahd_cmdsize_table_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x158, regvalue, cur_col, wrap));
 }
 
+int
+ahd_mk_message_scb_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(NULL, 0, "MK_MESSAGE_SCB",
+           0x160, regvalue, cur_col, wrap));
+}
+
+int
+ahd_mk_message_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(NULL, 0, "MK_MESSAGE_SCSIID",
+           0x162, regvalue, cur_col, wrap));
+}
+
 int
 ahd_scb_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
index b1e5365be23005f11957da625356bd7c0f147c20..11bed07e90b7ef8573ae0d5fc5afcb7f3211ab07 100644 (file)
@@ -2,17 +2,17 @@
  * DO NOT EDIT - This file is automatically generated
  *              from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#119 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#76 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#120 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#77 $
  */
 static uint8_t seqprog[] = {
        0xff, 0x02, 0x06, 0x78,
-       0x00, 0xea, 0x64, 0x59,
+       0x00, 0xea, 0x6e, 0x59,
        0x01, 0xea, 0x04, 0x30,
        0xff, 0x04, 0x0c, 0x78,
-       0x19, 0xea, 0x64, 0x59,
+       0x19, 0xea, 0x6e, 0x59,
        0x19, 0xea, 0x04, 0x00,
-       0x33, 0xea, 0x5e, 0x59,
+       0x33, 0xea, 0x68, 0x59,
        0x33, 0xea, 0x00, 0x00,
        0x60, 0x3a, 0x3a, 0x68,
        0x04, 0x4d, 0x35, 0x78,
@@ -33,15 +33,15 @@ static uint8_t seqprog[] = {
        0xff, 0xea, 0x62, 0x02,
        0x00, 0xe2, 0x3a, 0x40,
        0xff, 0x21, 0x3b, 0x70,
-       0x40, 0x4b, 0xaa, 0x69,
-       0x00, 0xe2, 0x68, 0x59,
-       0x40, 0x4b, 0xaa, 0x69,
-       0x20, 0x4b, 0x96, 0x69,
+       0x40, 0x4b, 0xb4, 0x69,
+       0x00, 0xe2, 0x72, 0x59,
+       0x40, 0x4b, 0xb4, 0x69,
+       0x20, 0x4b, 0xa0, 0x69,
        0xfc, 0x42, 0x44, 0x78,
        0x10, 0x40, 0x44, 0x78,
-       0x00, 0xe2, 0xfc, 0x5d,
+       0x00, 0xe2, 0x10, 0x5e,
        0x20, 0x4d, 0x48, 0x78,
-       0x00, 0xe2, 0xfc, 0x5d,
+       0x00, 0xe2, 0x10, 0x5e,
        0x30, 0x3f, 0xc0, 0x09,
        0x30, 0xe0, 0x50, 0x60,
        0x7f, 0x4a, 0x94, 0x08,
@@ -51,7 +51,7 @@ static uint8_t seqprog[] = {
        0x00, 0xe2, 0x76, 0x58,
        0x00, 0xe2, 0x86, 0x58,
        0x00, 0xe2, 0x06, 0x40,
-       0x33, 0xea, 0x5e, 0x59,
+       0x33, 0xea, 0x68, 0x59,
        0x33, 0xea, 0x00, 0x00,
        0x01, 0x52, 0x84, 0x78,
        0x02, 0x58, 0x50, 0x31,
@@ -59,26 +59,26 @@ static uint8_t seqprog[] = {
        0xff, 0x97, 0x6f, 0x78,
        0x50, 0x4b, 0x6a, 0x68,
        0xbf, 0x3a, 0x74, 0x08,
-       0x14, 0xea, 0x64, 0x59,
+       0x14, 0xea, 0x6e, 0x59,
        0x14, 0xea, 0x04, 0x00,
        0x08, 0x92, 0x25, 0x03,
        0xff, 0x90, 0x5f, 0x68,
-       0x00, 0xe2, 0x76, 0x5b,
+       0x00, 0xe2, 0x8a, 0x5b,
        0x00, 0xe2, 0x5e, 0x40,
-       0x00, 0xea, 0x5e, 0x59,
+       0x00, 0xea, 0x68, 0x59,
        0x01, 0xea, 0x00, 0x30,
        0x80, 0xf9, 0x7e, 0x68,
-       0x00, 0xe2, 0x5c, 0x59,
-       0x11, 0xea, 0x5e, 0x59,
+       0x00, 0xe2, 0x66, 0x59,
+       0x11, 0xea, 0x68, 0x59,
        0x11, 0xea, 0x00, 0x00,
-       0x80, 0xf9, 0x5c, 0x79,
+       0x80, 0xf9, 0x66, 0x79,
        0xff, 0xea, 0xd4, 0x0d,
-       0x22, 0xea, 0x5e, 0x59,
+       0x22, 0xea, 0x68, 0x59,
        0x22, 0xea, 0x00, 0x00,
        0x10, 0x16, 0x90, 0x78,
        0x10, 0x16, 0x2c, 0x00,
        0x01, 0x0b, 0xae, 0x32,
-       0x18, 0xad, 0x12, 0x79,
+       0x18, 0xad, 0x1c, 0x79,
        0x04, 0xad, 0xdc, 0x68,
        0x80, 0xad, 0x84, 0x78,
        0x10, 0xad, 0xaa, 0x78,
@@ -118,7 +118,6 @@ static uint8_t seqprog[] = {
        0x80, 0x18, 0x30, 0x04,
        0x40, 0xad, 0x84, 0x78,
        0xe7, 0xad, 0x5a, 0x09,
-       0x02, 0xa8, 0x40, 0x31,
        0xff, 0xea, 0xc0, 0x09,
        0x01, 0x54, 0xa9, 0x1a,
        0x00, 0x55, 0xab, 0x22,
@@ -128,24 +127,30 @@ static uint8_t seqprog[] = {
        0xff, 0xea, 0x5a, 0x03,
        0xff, 0xea, 0x5e, 0x03,
        0x01, 0x10, 0xd4, 0x31,
-       0x10, 0x92, 0x07, 0x69,
+       0x02, 0xa8, 0x40, 0x31,
+       0x01, 0x92, 0xc1, 0x31,
        0x3d, 0x93, 0xc5, 0x29,
        0xfe, 0xe2, 0xc4, 0x09,
        0x01, 0xea, 0xc6, 0x01,
        0x02, 0xe2, 0xc8, 0x31,
        0x02, 0xec, 0x50, 0x31,
        0x02, 0xa0, 0xda, 0x31,
-       0xff, 0xa9, 0x06, 0x71,
+       0xff, 0xa9, 0x10, 0x71,
+       0x10, 0xe0, 0x0e, 0x79,
+       0x10, 0x92, 0x0f, 0x79,
+       0x01, 0x4d, 0x9b, 0x02,
+       0x02, 0xa0, 0xc0, 0x32,
+       0x01, 0x93, 0xc5, 0x36,
        0x02, 0xa0, 0x58, 0x37,
-       0xff, 0x21, 0x0f, 0x71,
+       0xff, 0x21, 0x19, 0x71,
        0x02, 0x22, 0x51, 0x31,
        0x02, 0xa0, 0x5c, 0x33,
        0x02, 0xa0, 0x44, 0x36,
        0x02, 0xa0, 0x40, 0x32,
        0x02, 0xa0, 0x44, 0x36,
-       0x04, 0x4d, 0x17, 0x69,
-       0x40, 0x16, 0x48, 0x69,
-       0xff, 0x2d, 0x4d, 0x61,
+       0x05, 0x4d, 0x21, 0x69,
+       0x40, 0x16, 0x52, 0x69,
+       0xff, 0x2d, 0x57, 0x61,
        0xff, 0x29, 0x85, 0x70,
        0x02, 0x28, 0x55, 0x32,
        0x01, 0xea, 0x5a, 0x01,
@@ -159,22 +164,22 @@ static uint8_t seqprog[] = {
        0x01, 0x56, 0xad, 0x1a,
        0xff, 0x54, 0xa9, 0x1a,
        0xff, 0x55, 0xab, 0x22,
-       0xff, 0x8d, 0x41, 0x71,
-       0x80, 0xac, 0x40, 0x71,
-       0x20, 0x16, 0x40, 0x69,
+       0xff, 0x8d, 0x4b, 0x71,
+       0x80, 0xac, 0x4a, 0x71,
+       0x20, 0x16, 0x4a, 0x69,
        0x00, 0xac, 0xc4, 0x19,
-       0x07, 0xe2, 0x40, 0xf9,
+       0x07, 0xe2, 0x4a, 0xf9,
        0x02, 0x8c, 0x51, 0x31,
-       0x00, 0xe2, 0x24, 0x41,
+       0x00, 0xe2, 0x2e, 0x41,
        0x01, 0xac, 0x08, 0x31,
        0x09, 0xea, 0x5a, 0x01,
        0x02, 0x8c, 0x51, 0x32,
        0xff, 0xea, 0x1a, 0x07,
        0x04, 0x24, 0xf9, 0x30,
-       0x1d, 0xea, 0x52, 0x41,
+       0x1d, 0xea, 0x5c, 0x41,
        0x02, 0x2c, 0x51, 0x31,
        0x04, 0xa8, 0xf9, 0x30,
-       0x19, 0xea, 0x52, 0x41,
+       0x19, 0xea, 0x5c, 0x41,
        0x06, 0xea, 0x08, 0x81,
        0x01, 0xe2, 0x5a, 0x35,
        0x02, 0xf2, 0xf0, 0x31,
@@ -190,27 +195,27 @@ static uint8_t seqprog[] = {
        0x02, 0x20, 0xb9, 0x30,
        0x02, 0x20, 0x51, 0x31,
        0x4c, 0x93, 0xd7, 0x28,
-       0x10, 0x92, 0x77, 0x79,
+       0x10, 0x92, 0x81, 0x79,
        0x01, 0x6b, 0xc0, 0x30,
        0x02, 0x64, 0xc8, 0x00,
        0x40, 0x3a, 0x74, 0x04,
        0x00, 0xe2, 0x76, 0x58,
-       0x33, 0xea, 0x5e, 0x59,
+       0x33, 0xea, 0x68, 0x59,
        0x33, 0xea, 0x00, 0x00,
        0x30, 0x3f, 0xc0, 0x09,
-       0x30, 0xe0, 0x78, 0x61,
-       0x20, 0x3f, 0x8e, 0x69,
-       0x10, 0x3f, 0x78, 0x79,
+       0x30, 0xe0, 0x82, 0x61,
+       0x20, 0x3f, 0x98, 0x69,
+       0x10, 0x3f, 0x82, 0x79,
        0x02, 0xea, 0x7e, 0x00,
-       0x00, 0xea, 0x5e, 0x59,
+       0x00, 0xea, 0x68, 0x59,
        0x01, 0xea, 0x00, 0x30,
        0x02, 0x4e, 0x51, 0x35,
        0x01, 0xea, 0x7e, 0x00,
-       0x11, 0xea, 0x5e, 0x59,
+       0x11, 0xea, 0x68, 0x59,
        0x11, 0xea, 0x00, 0x00,
        0x02, 0x4e, 0x51, 0x35,
        0xc0, 0x4a, 0x94, 0x00,
-       0x04, 0x41, 0x9c, 0x79,
+       0x04, 0x41, 0xa6, 0x79,
        0x08, 0xea, 0x98, 0x00,
        0x08, 0x57, 0xae, 0x00,
        0x08, 0x3c, 0x78, 0x00,
@@ -218,12 +223,12 @@ static uint8_t seqprog[] = {
        0x0f, 0x67, 0xc0, 0x09,
        0x00, 0x3a, 0x75, 0x02,
        0x20, 0xea, 0x96, 0x00,
-       0x00, 0xe2, 0x14, 0x42,
+       0x00, 0xe2, 0x28, 0x42,
        0xc0, 0x4a, 0x94, 0x00,
-       0x40, 0x3a, 0xc8, 0x69,
+       0x40, 0x3a, 0xd2, 0x69,
        0x02, 0x55, 0x06, 0x68,
-       0x02, 0x56, 0xc8, 0x69,
-       0xff, 0x5b, 0xc8, 0x61,
+       0x02, 0x56, 0xd2, 0x69,
+       0xff, 0x5b, 0xd2, 0x61,
        0x02, 0x20, 0x51, 0x31,
        0x80, 0xea, 0xb2, 0x01,
        0x44, 0xea, 0x00, 0x00,
@@ -231,40 +236,45 @@ static uint8_t seqprog[] = {
        0x33, 0xea, 0x00, 0x00,
        0xff, 0xea, 0xb2, 0x09,
        0xff, 0xe0, 0xc0, 0x19,
-       0xff, 0xe0, 0xca, 0x79,
+       0xff, 0xe0, 0xd4, 0x79,
        0x02, 0xac, 0x51, 0x31,
-       0x00, 0xe2, 0xc0, 0x41,
+       0x00, 0xe2, 0xca, 0x41,
        0x02, 0x5e, 0x50, 0x31,
        0x02, 0xa8, 0xb8, 0x30,
        0x02, 0x5c, 0x50, 0x31,
-       0xff, 0xad, 0xdb, 0x71,
+       0xff, 0xad, 0xe5, 0x71,
        0x02, 0xac, 0x41, 0x31,
        0x02, 0x22, 0x51, 0x31,
        0x02, 0xa0, 0x5c, 0x33,
        0x02, 0xa0, 0x44, 0x32,
-       0x00, 0xe2, 0xe4, 0x41,
-       0x10, 0x92, 0xe5, 0x69,
+       0x00, 0xe2, 0xf8, 0x41,
+       0x01, 0x4d, 0xf1, 0x79,
+       0x01, 0x62, 0xc1, 0x31,
+       0x00, 0x93, 0xf1, 0x61,
+       0xfe, 0x4d, 0x9b, 0x0a,
+       0x02, 0x60, 0x41, 0x31,
+       0x00, 0xe2, 0xdc, 0x41,
        0x3d, 0x93, 0xc9, 0x29,
        0x01, 0xe4, 0xc8, 0x01,
        0x01, 0xea, 0xca, 0x01,
        0xff, 0xea, 0xda, 0x01,
        0x02, 0x20, 0x51, 0x31,
        0x02, 0xae, 0x41, 0x32,
-       0xff, 0x21, 0xed, 0x61,
+       0xff, 0x21, 0x01, 0x62,
        0xff, 0xea, 0x46, 0x02,
        0x02, 0x5c, 0x50, 0x31,
        0x40, 0xea, 0x96, 0x00,
-       0x02, 0x56, 0x04, 0x6e,
-       0x01, 0x55, 0x04, 0x6e,
-       0x10, 0x92, 0xf9, 0x79,
-       0x10, 0x40, 0x02, 0x6a,
-       0x01, 0x56, 0x02, 0x7a,
+       0x02, 0x56, 0x20, 0x6e,
+       0x01, 0x55, 0x20, 0x6e,
+       0x10, 0x92, 0x0d, 0x7a,
+       0x10, 0x40, 0x16, 0x6a,
+       0x01, 0x56, 0x16, 0x7a,
        0xff, 0x97, 0x07, 0x78,
-       0x13, 0xea, 0x64, 0x59,
+       0x13, 0xea, 0x6e, 0x59,
        0x13, 0xea, 0x04, 0x00,
        0x00, 0xe2, 0x06, 0x40,
        0xbf, 0x3a, 0x74, 0x08,
-       0x04, 0x41, 0x08, 0x7a,
+       0x04, 0x41, 0x1c, 0x7a,
        0x08, 0xea, 0x98, 0x00,
        0x08, 0x57, 0xae, 0x00,
        0x01, 0x93, 0x75, 0x32,
@@ -272,108 +282,108 @@ static uint8_t seqprog[] = {
        0x40, 0xea, 0x72, 0x02,
        0x08, 0x3c, 0x78, 0x00,
        0x80, 0xea, 0x6e, 0x02,
-       0x00, 0xe2, 0xe2, 0x5b,
+       0x00, 0xe2, 0xf6, 0x5b,
        0x01, 0x3c, 0xc1, 0x31,
-       0x9f, 0xe0, 0x84, 0x7c,
-       0x80, 0xe0, 0x28, 0x72,
-       0xa0, 0xe0, 0x64, 0x72,
-       0xc0, 0xe0, 0x5a, 0x72,
-       0xe0, 0xe0, 0x94, 0x72,
-       0x01, 0xea, 0x64, 0x59,
+       0x9f, 0xe0, 0x98, 0x7c,
+       0x80, 0xe0, 0x3c, 0x72,
+       0xa0, 0xe0, 0x78, 0x72,
+       0xc0, 0xe0, 0x6e, 0x72,
+       0xe0, 0xe0, 0xa8, 0x72,
+       0x01, 0xea, 0x6e, 0x59,
        0x01, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x14, 0x42,
-       0x80, 0x39, 0x2f, 0x7a,
-       0x03, 0xea, 0x64, 0x59,
+       0x00, 0xe2, 0x28, 0x42,
+       0x80, 0x39, 0x43, 0x7a,
+       0x03, 0xea, 0x6e, 0x59,
        0x03, 0xea, 0x04, 0x00,
-       0xee, 0x00, 0x36, 0x6a,
+       0xee, 0x00, 0x4a, 0x6a,
        0x05, 0xea, 0xb4, 0x00,
-       0x33, 0xea, 0x5e, 0x59,
+       0x33, 0xea, 0x68, 0x59,
        0x33, 0xea, 0x00, 0x00,
        0x02, 0xa8, 0x9c, 0x32,
-       0x00, 0xe2, 0x7e, 0x59,
+       0x00, 0xe2, 0x88, 0x59,
        0xef, 0x96, 0xd5, 0x19,
-       0x00, 0xe2, 0x46, 0x52,
+       0x00, 0xe2, 0x5a, 0x52,
        0x09, 0x80, 0xe1, 0x30,
        0x02, 0xea, 0x36, 0x00,
        0xa8, 0xea, 0x32, 0x00,
-       0x00, 0xe2, 0x4c, 0x42,
+       0x00, 0xe2, 0x60, 0x42,
        0x01, 0x96, 0xd1, 0x30,
        0x10, 0x80, 0x89, 0x31,
        0x20, 0xea, 0x32, 0x00,
        0xbf, 0x39, 0x73, 0x0a,
-       0x10, 0x4c, 0x56, 0x6a,
-       0x20, 0x19, 0x4e, 0x6a,
-       0x20, 0x19, 0x52, 0x6a,
-       0x02, 0x4d, 0x14, 0x6a,
+       0x10, 0x4c, 0x6a, 0x6a,
+       0x20, 0x19, 0x62, 0x6a,
+       0x20, 0x19, 0x66, 0x6a,
+       0x02, 0x4d, 0x28, 0x6a,
        0x40, 0x39, 0x73, 0x02,
-       0x00, 0xe2, 0x14, 0x42,
-       0x80, 0x39, 0xd5, 0x6a,
+       0x00, 0xe2, 0x28, 0x42,
+       0x80, 0x39, 0xe9, 0x6a,
        0x01, 0x44, 0x10, 0x33,
        0x08, 0x92, 0x25, 0x03,
-       0x00, 0xe2, 0x14, 0x42,
+       0x00, 0xe2, 0x28, 0x42,
        0x10, 0xea, 0x80, 0x00,
        0x01, 0x37, 0xc5, 0x31,
-       0x80, 0xe2, 0x80, 0x62,
-       0x10, 0x92, 0xa5, 0x6a,
+       0x80, 0xe2, 0x94, 0x62,
+       0x10, 0x92, 0xb9, 0x6a,
        0xc0, 0x94, 0xc5, 0x01,
-       0x40, 0x92, 0x71, 0x6a,
+       0x40, 0x92, 0x85, 0x6a,
        0xbf, 0xe2, 0xc4, 0x09,
-       0x20, 0x92, 0x85, 0x7a,
+       0x20, 0x92, 0x99, 0x7a,
        0x01, 0xe2, 0x88, 0x30,
-       0x00, 0xe2, 0xe2, 0x5b,
-       0xa0, 0x3c, 0x8d, 0x62,
+       0x00, 0xe2, 0xf6, 0x5b,
+       0xa0, 0x3c, 0xa1, 0x62,
        0x23, 0x92, 0x89, 0x08,
-       0x00, 0xe2, 0xe2, 0x5b,
-       0xa0, 0x3c, 0x8d, 0x62,
-       0x00, 0xa8, 0x84, 0x42,
-       0xff, 0xe2, 0x84, 0x62,
-       0x00, 0xe2, 0xa4, 0x42,
+       0x00, 0xe2, 0xf6, 0x5b,
+       0xa0, 0x3c, 0xa1, 0x62,
+       0x00, 0xa8, 0x98, 0x42,
+       0xff, 0xe2, 0x98, 0x62,
+       0x00, 0xe2, 0xb8, 0x42,
        0x40, 0xea, 0x98, 0x00,
        0x01, 0xe2, 0x88, 0x30,
-       0x00, 0xe2, 0xe2, 0x5b,
-       0xa0, 0x3c, 0x63, 0x72,
+       0x00, 0xe2, 0xf6, 0x5b,
+       0xa0, 0x3c, 0x77, 0x72,
        0x40, 0xea, 0x98, 0x00,
        0x01, 0x37, 0x95, 0x32,
        0x08, 0xea, 0x6e, 0x02,
-       0x00, 0xe2, 0x14, 0x42,
-       0xe0, 0xea, 0xfe, 0x5b,
-       0x80, 0xe0, 0xe0, 0x6a,
-       0x04, 0xe0, 0x92, 0x73,
-       0x02, 0xe0, 0xc4, 0x73,
-       0x00, 0xea, 0x3e, 0x73,
-       0x03, 0xe0, 0xd4, 0x73,
-       0x23, 0xe0, 0xb6, 0x72,
-       0x08, 0xe0, 0xdc, 0x72,
-       0x00, 0xe2, 0xe2, 0x5b,
-       0x07, 0xea, 0x64, 0x59,
+       0x00, 0xe2, 0x28, 0x42,
+       0xe0, 0xea, 0x12, 0x5c,
+       0x80, 0xe0, 0xf4, 0x6a,
+       0x04, 0xe0, 0xa6, 0x73,
+       0x02, 0xe0, 0xd8, 0x73,
+       0x00, 0xea, 0x52, 0x73,
+       0x03, 0xe0, 0xe8, 0x73,
+       0x23, 0xe0, 0xca, 0x72,
+       0x08, 0xe0, 0xf0, 0x72,
+       0x00, 0xe2, 0xf6, 0x5b,
+       0x07, 0xea, 0x6e, 0x59,
        0x07, 0xea, 0x04, 0x00,
-       0x08, 0x48, 0x15, 0x72,
-       0x04, 0x48, 0xb3, 0x62,
+       0x08, 0x48, 0x29, 0x72,
+       0x04, 0x48, 0xc7, 0x62,
        0x01, 0x49, 0x89, 0x30,
-       0x00, 0xe2, 0xa4, 0x42,
+       0x00, 0xe2, 0xb8, 0x42,
        0x01, 0x44, 0xd4, 0x31,
-       0x00, 0xe2, 0xa4, 0x42,
+       0x00, 0xe2, 0xb8, 0x42,
        0x01, 0x00, 0x6c, 0x32,
-       0x33, 0xea, 0x5e, 0x59,
+       0x33, 0xea, 0x68, 0x59,
        0x33, 0xea, 0x00, 0x00,
        0x4c, 0x3a, 0xc1, 0x28,
        0x01, 0x64, 0xc0, 0x31,
-       0x00, 0x36, 0x5f, 0x59,
+       0x00, 0x36, 0x69, 0x59,
        0x01, 0x36, 0x01, 0x30,
-       0x01, 0xe0, 0xda, 0x7a,
-       0xa0, 0xea, 0xf4, 0x5b,
-       0x01, 0xa0, 0xda, 0x62,
-       0x01, 0x84, 0xcf, 0x7a,
-       0x01, 0x95, 0xdd, 0x6a,
-       0x05, 0xea, 0x64, 0x59,
+       0x01, 0xe0, 0xee, 0x7a,
+       0xa0, 0xea, 0x08, 0x5c,
+       0x01, 0xa0, 0xee, 0x62,
+       0x01, 0x84, 0xe3, 0x7a,
+       0x01, 0x95, 0xf1, 0x6a,
+       0x05, 0xea, 0x6e, 0x59,
        0x05, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xdc, 0x42,
-       0x03, 0xea, 0x64, 0x59,
+       0x00, 0xe2, 0xf0, 0x42,
+       0x03, 0xea, 0x6e, 0x59,
        0x03, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xdc, 0x42,
-       0x07, 0xea, 0x06, 0x5c,
+       0x00, 0xe2, 0xf0, 0x42,
+       0x07, 0xea, 0x1a, 0x5c,
        0x01, 0x44, 0xd4, 0x31,
-       0x00, 0xe2, 0x14, 0x42,
+       0x00, 0xe2, 0x28, 0x42,
        0x3f, 0xe0, 0x76, 0x0a,
        0xc0, 0x3a, 0xc1, 0x09,
        0x00, 0x3b, 0x51, 0x01,
@@ -384,54 +394,54 @@ static uint8_t seqprog[] = {
        0x01, 0xea, 0xc6, 0x01,
        0x02, 0xe2, 0xc8, 0x31,
        0x02, 0xec, 0x40, 0x31,
-       0xff, 0xa1, 0xfc, 0x72,
+       0xff, 0xa1, 0x10, 0x73,
        0x02, 0xe8, 0xda, 0x31,
        0x02, 0xa0, 0x50, 0x31,
-       0x00, 0xe2, 0x1e, 0x43,
+       0x00, 0xe2, 0x32, 0x43,
        0x80, 0x39, 0x73, 0x02,
        0x01, 0x44, 0xd4, 0x31,
-       0x00, 0xe2, 0xe2, 0x5b,
+       0x00, 0xe2, 0xf6, 0x5b,
        0x01, 0x39, 0x73, 0x02,
-       0xe0, 0x3c, 0x39, 0x63,
+       0xe0, 0x3c, 0x4d, 0x63,
        0x02, 0x39, 0x73, 0x02,
-       0x20, 0x46, 0x32, 0x63,
+       0x20, 0x46, 0x46, 0x63,
        0xff, 0xea, 0x52, 0x09,
-       0xa8, 0xea, 0xf4, 0x5b,
-       0x04, 0x92, 0x19, 0x7b,
+       0xa8, 0xea, 0x08, 0x5c,
+       0x04, 0x92, 0x2d, 0x7b,
        0x01, 0x3a, 0xc1, 0x31,
-       0x00, 0x93, 0x19, 0x63,
+       0x00, 0x93, 0x2d, 0x63,
        0x01, 0x3b, 0xc1, 0x31,
-       0x00, 0x94, 0x23, 0x73,
+       0x00, 0x94, 0x37, 0x73,
        0x01, 0xa9, 0x52, 0x11,
-       0xff, 0xa9, 0x0e, 0x6b,
-       0x00, 0xe2, 0x32, 0x43,
+       0xff, 0xa9, 0x22, 0x6b,
+       0x00, 0xe2, 0x46, 0x43,
        0x10, 0x39, 0x73, 0x02,
-       0x04, 0x92, 0x33, 0x7b,
+       0x04, 0x92, 0x47, 0x7b,
        0xfb, 0x92, 0x25, 0x0b,
        0xff, 0xea, 0x72, 0x0a,
-       0x01, 0xa4, 0x2d, 0x6b,
+       0x01, 0xa4, 0x41, 0x6b,
        0x02, 0xa8, 0x9c, 0x32,
-       0x00, 0xe2, 0x7e, 0x59,
-       0x10, 0x92, 0xdd, 0x7a,
-       0xff, 0xea, 0x06, 0x5c,
-       0x00, 0xe2, 0xdc, 0x42,
-       0x04, 0xea, 0x64, 0x59,
+       0x00, 0xe2, 0x88, 0x59,
+       0x10, 0x92, 0xf1, 0x7a,
+       0xff, 0xea, 0x1a, 0x5c,
+       0x00, 0xe2, 0xf0, 0x42,
+       0x04, 0xea, 0x6e, 0x59,
        0x04, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xdc, 0x42,
-       0x04, 0xea, 0x64, 0x59,
+       0x00, 0xe2, 0xf0, 0x42,
+       0x04, 0xea, 0x6e, 0x59,
        0x04, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x14, 0x42,
-       0x08, 0x92, 0xd5, 0x7a,
-       0xc0, 0x39, 0x49, 0x7b,
-       0x80, 0x39, 0xd5, 0x6a,
-       0xff, 0x88, 0x49, 0x6b,
-       0x40, 0x39, 0xd5, 0x6a,
-       0x10, 0x92, 0x4f, 0x7b,
-       0x0a, 0xea, 0x64, 0x59,
+       0x00, 0xe2, 0x28, 0x42,
+       0x08, 0x92, 0xe9, 0x7a,
+       0xc0, 0x39, 0x5d, 0x7b,
+       0x80, 0x39, 0xe9, 0x6a,
+       0xff, 0x88, 0x5d, 0x6b,
+       0x40, 0x39, 0xe9, 0x6a,
+       0x10, 0x92, 0x63, 0x7b,
+       0x0a, 0xea, 0x6e, 0x59,
        0x0a, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x6e, 0x5b,
-       0x00, 0xe2, 0xae, 0x43,
-       0x50, 0x4b, 0x56, 0x6b,
+       0x00, 0xe2, 0x82, 0x5b,
+       0x00, 0xe2, 0xc2, 0x43,
+       0x50, 0x4b, 0x6a, 0x6b,
        0xbf, 0x3a, 0x74, 0x08,
        0x01, 0xe0, 0xf4, 0x31,
        0xff, 0xea, 0xc0, 0x09,
@@ -441,31 +451,31 @@ static uint8_t seqprog[] = {
        0x01, 0xfa, 0xc0, 0x35,
        0x02, 0xa8, 0x90, 0x32,
        0x02, 0xea, 0xb4, 0x00,
-       0x33, 0xea, 0x5e, 0x59,
+       0x33, 0xea, 0x68, 0x59,
        0x33, 0xea, 0x00, 0x00,
        0x02, 0x48, 0x51, 0x31,
        0xff, 0x90, 0x85, 0x68,
-       0xff, 0x88, 0x7b, 0x6b,
-       0x01, 0xa4, 0x77, 0x6b,
-       0x02, 0xa4, 0x7f, 0x6b,
-       0x01, 0x84, 0x7f, 0x7b,
+       0xff, 0x88, 0x8f, 0x6b,
+       0x01, 0xa4, 0x8b, 0x6b,
+       0x02, 0xa4, 0x93, 0x6b,
+       0x01, 0x84, 0x93, 0x7b,
        0x02, 0x28, 0x19, 0x33,
        0x02, 0xa8, 0x50, 0x36,
-       0xff, 0x88, 0x7f, 0x73,
-       0x00, 0xe2, 0x52, 0x5b,
+       0xff, 0x88, 0x93, 0x73,
+       0x00, 0xe2, 0x66, 0x5b,
        0x02, 0xa8, 0x20, 0x33,
        0x04, 0xa4, 0x49, 0x03,
        0xff, 0xea, 0x1a, 0x03,
-       0xff, 0x2d, 0x8b, 0x63,
+       0xff, 0x2d, 0x9f, 0x63,
        0x02, 0xa8, 0x58, 0x32,
        0x02, 0xa8, 0x5c, 0x36,
        0x02, 0xa8, 0x40, 0x31,
        0x02, 0x2e, 0x51, 0x31,
        0x02, 0xa0, 0x18, 0x33,
        0x02, 0xa0, 0x5c, 0x36,
-       0xc0, 0x39, 0xd5, 0x6a,
+       0xc0, 0x39, 0xe9, 0x6a,
        0x04, 0x92, 0x25, 0x03,
-       0x20, 0x92, 0xaf, 0x6b,
+       0x20, 0x92, 0xc3, 0x6b,
        0x02, 0xa8, 0x40, 0x31,
        0xc0, 0x3a, 0xc1, 0x09,
        0x00, 0x3b, 0x51, 0x01,
@@ -480,60 +490,60 @@ static uint8_t seqprog[] = {
        0xf7, 0x57, 0xae, 0x08,
        0x08, 0xea, 0x98, 0x00,
        0x01, 0x44, 0xd4, 0x31,
-       0xee, 0x00, 0xb8, 0x6b,
+       0xee, 0x00, 0xcc, 0x6b,
        0x02, 0xea, 0xb4, 0x00,
        0xc0, 0xea, 0x72, 0x02,
-       0x09, 0x4c, 0xba, 0x7b,
+       0x09, 0x4c, 0xce, 0x7b,
        0x01, 0xea, 0x78, 0x02,
        0x08, 0x4c, 0x06, 0x68,
-       0x0b, 0xea, 0x64, 0x59,
+       0x0b, 0xea, 0x6e, 0x59,
        0x0b, 0xea, 0x04, 0x00,
        0x01, 0x44, 0xd4, 0x31,
-       0x20, 0x39, 0x15, 0x7a,
-       0x00, 0xe2, 0xcc, 0x5b,
-       0x00, 0xe2, 0x14, 0x42,
-       0x01, 0x84, 0xd1, 0x7b,
+       0x20, 0x39, 0x29, 0x7a,
+       0x00, 0xe2, 0xe0, 0x5b,
+       0x00, 0xe2, 0x28, 0x42,
+       0x01, 0x84, 0xe5, 0x7b,
        0x01, 0xa4, 0x49, 0x07,
        0x08, 0x60, 0x30, 0x33,
        0x08, 0x80, 0x41, 0x37,
        0xdf, 0x39, 0x73, 0x0a,
-       0xee, 0x00, 0xde, 0x6b,
+       0xee, 0x00, 0xf2, 0x6b,
        0x05, 0xea, 0xb4, 0x00,
-       0x33, 0xea, 0x5e, 0x59,
+       0x33, 0xea, 0x68, 0x59,
        0x33, 0xea, 0x00, 0x00,
-       0x00, 0xe2, 0x7e, 0x59,
-       0x00, 0xe2, 0xdc, 0x42,
-       0xff, 0x42, 0xee, 0x6b,
-       0x01, 0x41, 0xe2, 0x6b,
-       0x02, 0x41, 0xe2, 0x7b,
-       0xff, 0x42, 0xee, 0x6b,
-       0x01, 0x41, 0xe2, 0x6b,
-       0x02, 0x41, 0xe2, 0x7b,
-       0xff, 0x42, 0xee, 0x7b,
-       0x04, 0x4c, 0xe2, 0x6b,
+       0x00, 0xe2, 0x88, 0x59,
+       0x00, 0xe2, 0xf0, 0x42,
+       0xff, 0x42, 0x02, 0x6c,
+       0x01, 0x41, 0xf6, 0x6b,
+       0x02, 0x41, 0xf6, 0x7b,
+       0xff, 0x42, 0x02, 0x6c,
+       0x01, 0x41, 0xf6, 0x6b,
+       0x02, 0x41, 0xf6, 0x7b,
+       0xff, 0x42, 0x02, 0x7c,
+       0x04, 0x4c, 0xf6, 0x6b,
        0xe0, 0x41, 0x78, 0x0e,
        0x01, 0x44, 0xd4, 0x31,
-       0xff, 0x42, 0xf6, 0x7b,
-       0x04, 0x4c, 0xf6, 0x6b,
+       0xff, 0x42, 0x0a, 0x7c,
+       0x04, 0x4c, 0x0a, 0x6c,
        0xe0, 0x41, 0x78, 0x0a,
-       0xe0, 0x3c, 0x15, 0x62,
+       0xe0, 0x3c, 0x29, 0x62,
        0xff, 0xea, 0xca, 0x09,
        0x01, 0xe2, 0xc8, 0x31,
        0x01, 0x46, 0xda, 0x35,
        0x01, 0x44, 0xd4, 0x35,
        0x10, 0xea, 0x80, 0x00,
        0x01, 0xe2, 0x6e, 0x36,
-       0x04, 0xa6, 0x0e, 0x7c,
+       0x04, 0xa6, 0x22, 0x7c,
        0xff, 0xea, 0x5a, 0x09,
        0xff, 0xea, 0x4c, 0x0d,
-       0x01, 0xa6, 0x3a, 0x6c,
+       0x01, 0xa6, 0x4e, 0x6c,
        0x10, 0xad, 0x84, 0x78,
-       0x80, 0xad, 0x32, 0x6c,
+       0x80, 0xad, 0x46, 0x6c,
        0x08, 0xad, 0x84, 0x68,
-       0x20, 0x19, 0x26, 0x7c,
+       0x20, 0x19, 0x3a, 0x7c,
        0x80, 0xea, 0xb2, 0x01,
        0x11, 0x00, 0x00, 0x10,
-       0x02, 0xa6, 0x22, 0x7c,
+       0x02, 0xa6, 0x36, 0x7c,
        0xff, 0xea, 0xb2, 0x0d,
        0x11, 0x00, 0x00, 0x10,
        0xff, 0xea, 0xb2, 0x09,
@@ -561,7 +571,7 @@ static uint8_t seqprog[] = {
        0x00, 0x86, 0x0d, 0x23,
        0x00, 0x87, 0x0f, 0x23,
        0x01, 0x84, 0xc5, 0x31,
-       0x80, 0x83, 0x5d, 0x7c,
+       0x80, 0x83, 0x71, 0x7c,
        0x02, 0xe2, 0xc4, 0x01,
        0xff, 0xea, 0x4c, 0x09,
        0x01, 0xe2, 0x36, 0x30,
@@ -572,75 +582,75 @@ static uint8_t seqprog[] = {
        0xfe, 0xa6, 0x4c, 0x0d,
        0x0b, 0x98, 0xe1, 0x30,
        0xfd, 0xa4, 0x49, 0x09,
-       0x80, 0xa3, 0x71, 0x7c,
+       0x80, 0xa3, 0x85, 0x7c,
        0x02, 0xa4, 0x48, 0x01,
        0x01, 0xa4, 0x36, 0x30,
        0xa8, 0xea, 0x32, 0x00,
        0xfd, 0xa4, 0x49, 0x0b,
        0x05, 0xa3, 0x07, 0x33,
-       0x80, 0x83, 0x7d, 0x6c,
+       0x80, 0x83, 0x91, 0x6c,
        0x02, 0xea, 0x4c, 0x05,
        0xff, 0xea, 0x4c, 0x0d,
-       0x00, 0xe2, 0x56, 0x59,
-       0x02, 0xa6, 0x10, 0x6c,
+       0x00, 0xe2, 0x60, 0x59,
+       0x02, 0xa6, 0x24, 0x6c,
        0x80, 0xf9, 0xf2, 0x05,
-       0xc0, 0x39, 0x8b, 0x7c,
-       0x03, 0xea, 0x64, 0x59,
+       0xc0, 0x39, 0x9f, 0x7c,
+       0x03, 0xea, 0x6e, 0x59,
        0x03, 0xea, 0x04, 0x00,
-       0x20, 0x39, 0xaf, 0x7c,
-       0x01, 0x84, 0x95, 0x6c,
-       0x06, 0xea, 0x64, 0x59,
+       0x20, 0x39, 0xc3, 0x7c,
+       0x01, 0x84, 0xa9, 0x6c,
+       0x06, 0xea, 0x6e, 0x59,
        0x06, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xb2, 0x44,
+       0x00, 0xe2, 0xc6, 0x44,
        0x01, 0x00, 0x6c, 0x32,
-       0xee, 0x00, 0x9e, 0x6c,
+       0xee, 0x00, 0xb2, 0x6c,
        0x05, 0xea, 0xb4, 0x00,
-       0x33, 0xea, 0x5e, 0x59,
+       0x33, 0xea, 0x68, 0x59,
        0x33, 0xea, 0x00, 0x00,
        0x80, 0x3d, 0x7a, 0x00,
-       0xfc, 0x42, 0xa0, 0x7c,
+       0xfc, 0x42, 0xb4, 0x7c,
        0x7f, 0x3d, 0x7a, 0x08,
-       0x00, 0x36, 0x5f, 0x59,
+       0x00, 0x36, 0x69, 0x59,
        0x01, 0x36, 0x01, 0x30,
-       0x09, 0xea, 0x64, 0x59,
+       0x09, 0xea, 0x6e, 0x59,
        0x09, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x14, 0x42,
-       0x01, 0xa4, 0x95, 0x6c,
-       0x00, 0xe2, 0x68, 0x5c,
+       0x00, 0xe2, 0x28, 0x42,
+       0x01, 0xa4, 0xa9, 0x6c,
+       0x00, 0xe2, 0x7c, 0x5c,
        0x20, 0x39, 0x73, 0x02,
        0x01, 0x00, 0x6c, 0x32,
-       0x02, 0xa6, 0xba, 0x7c,
-       0x00, 0xe2, 0x7e, 0x5c,
+       0x02, 0xa6, 0xce, 0x7c,
+       0x00, 0xe2, 0x92, 0x5c,
        0x00, 0xe2, 0x76, 0x58,
        0x00, 0xe2, 0x86, 0x58,
        0x00, 0xe2, 0x5a, 0x58,
-       0x00, 0x36, 0x5f, 0x59,
+       0x00, 0x36, 0x69, 0x59,
        0x01, 0x36, 0x01, 0x30,
-       0x20, 0x19, 0xba, 0x6c,
-       0x00, 0xe2, 0xea, 0x5c,
-       0x04, 0x19, 0xd4, 0x6c,
+       0x20, 0x19, 0xce, 0x6c,
+       0x00, 0xe2, 0xfe, 0x5c,
+       0x04, 0x19, 0xe8, 0x6c,
        0x02, 0x19, 0x32, 0x00,
-       0x01, 0x84, 0xd5, 0x7c,
-       0x01, 0x1b, 0xce, 0x7c,
-       0x01, 0x1a, 0xd4, 0x6c,
-       0x00, 0xe2, 0x84, 0x44,
-       0x80, 0x4b, 0xda, 0x6c,
-       0x01, 0x4c, 0xd6, 0x7c,
-       0x03, 0x42, 0x84, 0x6c,
-       0x00, 0xe2, 0x0a, 0x5c,
+       0x01, 0x84, 0xe9, 0x7c,
+       0x01, 0x1b, 0xe2, 0x7c,
+       0x01, 0x1a, 0xe8, 0x6c,
+       0x00, 0xe2, 0x98, 0x44,
+       0x80, 0x4b, 0xee, 0x6c,
+       0x01, 0x4c, 0xea, 0x7c,
+       0x03, 0x42, 0x98, 0x6c,
+       0x00, 0xe2, 0x1e, 0x5c,
        0x80, 0xf9, 0xf2, 0x01,
-       0x04, 0x39, 0x15, 0x7a,
-       0x00, 0xe2, 0x14, 0x42,
-       0x08, 0x5d, 0xf2, 0x6c,
+       0x04, 0x39, 0x29, 0x7a,
+       0x00, 0xe2, 0x28, 0x42,
+       0x08, 0x5d, 0x06, 0x6d,
        0x00, 0xe2, 0x76, 0x58,
-       0x00, 0x36, 0x5f, 0x59,
+       0x00, 0x36, 0x69, 0x59,
        0x01, 0x36, 0x01, 0x30,
-       0x02, 0x1b, 0xe2, 0x7c,
-       0x08, 0x5d, 0xf0, 0x7c,
+       0x02, 0x1b, 0xf6, 0x7c,
+       0x08, 0x5d, 0x04, 0x7d,
        0x03, 0x68, 0x00, 0x37,
        0x01, 0x84, 0x09, 0x07,
-       0x80, 0x1b, 0xfc, 0x7c,
-       0x80, 0x84, 0xfd, 0x6c,
+       0x80, 0x1b, 0x10, 0x7d,
+       0x80, 0x84, 0x11, 0x6d,
        0xff, 0x85, 0x0b, 0x1b,
        0xff, 0x86, 0x0d, 0x23,
        0xff, 0x87, 0x0f, 0x23,
@@ -652,161 +662,164 @@ static uint8_t seqprog[] = {
        0xf9, 0xd9, 0xb2, 0x0d,
        0x01, 0xd9, 0xb2, 0x05,
        0x01, 0x52, 0x48, 0x31,
-       0x20, 0xa4, 0x26, 0x7d,
-       0x20, 0x5b, 0x26, 0x7d,
-       0x80, 0xf9, 0x34, 0x7d,
+       0x20, 0xa4, 0x3a, 0x7d,
+       0x20, 0x5b, 0x3a, 0x7d,
+       0x80, 0xf9, 0x48, 0x7d,
        0x02, 0xea, 0xb4, 0x00,
        0x11, 0x00, 0x00, 0x10,
-       0x04, 0x19, 0x40, 0x7d,
+       0x04, 0x19, 0x54, 0x7d,
        0xdf, 0x19, 0x32, 0x08,
-       0x60, 0x5b, 0x40, 0x6d,
-       0x01, 0x4c, 0x1a, 0x7d,
+       0x60, 0x5b, 0x54, 0x6d,
+       0x01, 0x4c, 0x2e, 0x7d,
        0x20, 0x19, 0x32, 0x00,
        0x01, 0xd9, 0xb2, 0x05,
        0x02, 0xea, 0xb4, 0x00,
        0x01, 0xd9, 0xb2, 0x05,
-       0x10, 0x5b, 0x38, 0x6d,
-       0x08, 0x5b, 0x42, 0x6d,
-       0x20, 0x5b, 0x32, 0x6d,
-       0x02, 0x5b, 0x62, 0x6d,
-       0x0e, 0xea, 0x64, 0x59,
+       0x10, 0x5b, 0x4c, 0x6d,
+       0x08, 0x5b, 0x56, 0x6d,
+       0x20, 0x5b, 0x46, 0x6d,
+       0x02, 0x5b, 0x76, 0x6d,
+       0x0e, 0xea, 0x6e, 0x59,
        0x0e, 0xea, 0x04, 0x00,
-       0x80, 0xf9, 0x22, 0x6d,
+       0x80, 0xf9, 0x36, 0x6d,
        0xdf, 0x5c, 0xb8, 0x08,
        0x01, 0xd9, 0xb2, 0x05,
-       0x01, 0xa4, 0x1d, 0x6e,
-       0x00, 0xe2, 0x68, 0x5c,
-       0x00, 0xe2, 0x6c, 0x5d,
+       0x01, 0xa4, 0x37, 0x6e,
+       0x00, 0xe2, 0x7c, 0x5c,
+       0x00, 0xe2, 0x80, 0x5d,
        0x01, 0x90, 0x21, 0x1b,
        0x01, 0xd9, 0xb2, 0x05,
-       0x00, 0xe2, 0x52, 0x5b,
+       0x00, 0xe2, 0x66, 0x5b,
        0xf3, 0x96, 0xd5, 0x19,
-       0x00, 0xe2, 0x50, 0x55,
-       0x80, 0x96, 0x51, 0x6d,
-       0x0f, 0xea, 0x64, 0x59,
+       0x00, 0xe2, 0x64, 0x55,
+       0x80, 0x96, 0x65, 0x6d,
+       0x0f, 0xea, 0x6e, 0x59,
        0x0f, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x58, 0x45,
+       0x00, 0xe2, 0x6c, 0x45,
        0x04, 0x8c, 0xe1, 0x30,
        0x01, 0xea, 0xf2, 0x00,
        0x02, 0xea, 0x36, 0x00,
        0xa8, 0xea, 0x32, 0x00,
-       0xff, 0x97, 0x5f, 0x7d,
-       0x14, 0xea, 0x64, 0x59,
+       0xff, 0x97, 0x73, 0x7d,
+       0x14, 0xea, 0x6e, 0x59,
        0x14, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xce, 0x5d,
+       0x00, 0xe2, 0xe2, 0x5d,
        0x01, 0xd9, 0xb2, 0x05,
        0x09, 0x80, 0xe1, 0x30,
        0x02, 0xea, 0x36, 0x00,
        0xa8, 0xea, 0x32, 0x00,
-       0x00, 0xe2, 0xc6, 0x5d,
+       0x00, 0xe2, 0xda, 0x5d,
        0x01, 0xd9, 0xb2, 0x05,
-       0x02, 0xa6, 0x7c, 0x7d,
-       0x00, 0xe2, 0x56, 0x59,
-       0x20, 0x5b, 0x8a, 0x6d,
-       0xfc, 0x42, 0x76, 0x7d,
-       0x10, 0x40, 0x78, 0x6d,
-       0x20, 0x4d, 0x7a, 0x7d,
-       0x08, 0x5d, 0x8a, 0x6d,
-       0x02, 0xa6, 0x10, 0x6c,
-       0x00, 0xe2, 0x56, 0x59,
-       0x20, 0x5b, 0x8a, 0x6d,
-       0x01, 0x1b, 0xaa, 0x6d,
-       0xfc, 0x42, 0x86, 0x7d,
-       0x10, 0x40, 0x88, 0x6d,
+       0x02, 0xa6, 0x90, 0x7d,
+       0x00, 0xe2, 0x60, 0x59,
+       0x20, 0x5b, 0x9e, 0x6d,
+       0xfc, 0x42, 0x8a, 0x7d,
+       0x10, 0x40, 0x8c, 0x6d,
+       0x20, 0x4d, 0x8e, 0x7d,
+       0x08, 0x5d, 0x9e, 0x6d,
+       0x02, 0xa6, 0x24, 0x6c,
+       0x00, 0xe2, 0x60, 0x59,
+       0x20, 0x5b, 0x9e, 0x6d,
+       0x01, 0x1b, 0xbe, 0x6d,
+       0xfc, 0x42, 0x9a, 0x7d,
+       0x10, 0x40, 0x9c, 0x6d,
        0x20, 0x4d, 0x84, 0x78,
        0x08, 0x5d, 0x84, 0x78,
        0x02, 0x19, 0x32, 0x00,
        0x01, 0x5b, 0x40, 0x31,
-       0x00, 0xe2, 0xea, 0x5c,
-       0x00, 0xe2, 0xcc, 0x5b,
+       0x00, 0xe2, 0xfe, 0x5c,
+       0x00, 0xe2, 0xe0, 0x5b,
        0x20, 0xea, 0xb6, 0x00,
-       0x00, 0xe2, 0x0a, 0x5c,
+       0x00, 0xe2, 0x1e, 0x5c,
        0x20, 0x5c, 0xb8, 0x00,
-       0x04, 0x19, 0xa0, 0x6d,
-       0x01, 0x1a, 0xa0, 0x6d,
-       0x00, 0xe2, 0x56, 0x59,
+       0x04, 0x19, 0xb4, 0x6d,
+       0x01, 0x1a, 0xb4, 0x6d,
+       0x00, 0xe2, 0x60, 0x59,
        0x01, 0x1a, 0x84, 0x78,
        0x80, 0xf9, 0xf2, 0x01,
-       0x20, 0xa0, 0x04, 0x7e,
+       0x20, 0xa0, 0x18, 0x7e,
        0xff, 0x90, 0x21, 0x1b,
-       0x08, 0x92, 0x63, 0x6b,
+       0x08, 0x92, 0x77, 0x6b,
        0x02, 0xea, 0xb4, 0x04,
        0x01, 0xa4, 0x49, 0x03,
-       0x40, 0x5b, 0xba, 0x6d,
-       0x00, 0xe2, 0x56, 0x59,
-       0x40, 0x5b, 0xba, 0x6d,
-       0x04, 0x5d, 0x1e, 0x7e,
-       0x01, 0x1a, 0x1e, 0x7e,
+       0x40, 0x5b, 0xce, 0x6d,
+       0x00, 0xe2, 0x60, 0x59,
+       0x40, 0x5b, 0xce, 0x6d,
+       0x04, 0x5d, 0x38, 0x7e,
+       0x01, 0x1a, 0x38, 0x7e,
        0x20, 0x4d, 0x84, 0x78,
-       0x40, 0x5b, 0x04, 0x7e,
-       0x04, 0x5d, 0x1e, 0x7e,
-       0x01, 0x1a, 0x1e, 0x7e,
+       0x40, 0x5b, 0x18, 0x7e,
+       0x04, 0x5d, 0x38, 0x7e,
+       0x01, 0x1a, 0x38, 0x7e,
        0x80, 0xf9, 0xf2, 0x01,
        0xff, 0x90, 0x21, 0x1b,
-       0x08, 0x92, 0x63, 0x6b,
+       0x08, 0x92, 0x77, 0x6b,
        0x02, 0xea, 0xb4, 0x04,
-       0x00, 0xe2, 0x56, 0x59,
+       0x00, 0xe2, 0x60, 0x59,
        0x01, 0x1b, 0x84, 0x78,
        0x80, 0xf9, 0xf2, 0x01,
        0x02, 0xea, 0xb4, 0x04,
-       0x00, 0xe2, 0x56, 0x59,
-       0x01, 0x1b, 0xe2, 0x6d,
-       0x40, 0x5b, 0xf0, 0x7d,
-       0x01, 0x1b, 0xe2, 0x6d,
+       0x00, 0xe2, 0x60, 0x59,
+       0x01, 0x1b, 0xf6, 0x6d,
+       0x40, 0x5b, 0x04, 0x7e,
+       0x01, 0x1b, 0xf6, 0x6d,
        0x02, 0x19, 0x32, 0x00,
        0x01, 0x1a, 0x84, 0x78,
        0x80, 0xf9, 0xf2, 0x01,
        0xff, 0xea, 0x10, 0x03,
        0x08, 0x92, 0x25, 0x03,
-       0x00, 0xe2, 0x62, 0x43,
-       0x01, 0x1a, 0xec, 0x7d,
-       0x40, 0x5b, 0xe8, 0x7d,
-       0x01, 0x1a, 0xd6, 0x6d,
+       0x00, 0xe2, 0x76, 0x43,
+       0x01, 0x1a, 0x00, 0x7e,
+       0x40, 0x5b, 0xfc, 0x7d,
+       0x01, 0x1a, 0xea, 0x6d,
        0xfc, 0x42, 0x84, 0x78,
-       0x01, 0x1a, 0xf0, 0x6d,
-       0x10, 0xea, 0x64, 0x59,
+       0x01, 0x1a, 0x04, 0x6e,
+       0x10, 0xea, 0x6e, 0x59,
        0x10, 0xea, 0x04, 0x00,
        0xfc, 0x42, 0x84, 0x78,
-       0x10, 0x40, 0xf6, 0x6d,
+       0x10, 0x40, 0x0a, 0x6e,
        0x20, 0x4d, 0x84, 0x78,
-       0x40, 0x5b, 0xd6, 0x6d,
+       0x40, 0x5b, 0xea, 0x6d,
        0x01, 0x1a, 0x84, 0x78,
        0x01, 0x90, 0x21, 0x1b,
        0x30, 0x3f, 0xc0, 0x09,
        0x30, 0xe0, 0x84, 0x60,
        0x40, 0x4b, 0x84, 0x68,
        0xff, 0xea, 0x52, 0x01,
-       0xee, 0x00, 0x0c, 0x6e,
+       0xee, 0x00, 0x20, 0x6e,
        0x80, 0xf9, 0xf2, 0x01,
        0xff, 0x90, 0x21, 0x1b,
        0x02, 0xea, 0xb4, 0x00,
        0x20, 0xea, 0x9a, 0x00,
-       0xf3, 0x42, 0x16, 0x6e,
-       0x12, 0xea, 0x64, 0x59,
+       0x04, 0x41, 0x26, 0x7e,
+       0x08, 0xea, 0x98, 0x00,
+       0x08, 0x57, 0xae, 0x00,
+       0xf3, 0x42, 0x30, 0x6e,
+       0x12, 0xea, 0x6e, 0x59,
        0x12, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x14, 0x42,
-       0x0d, 0xea, 0x64, 0x59,
+       0x00, 0xe2, 0x28, 0x42,
+       0x0d, 0xea, 0x6e, 0x59,
        0x0d, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x14, 0x42,
+       0x00, 0xe2, 0x28, 0x42,
        0x01, 0x90, 0x21, 0x1b,
-       0x11, 0xea, 0x64, 0x59,
+       0x11, 0xea, 0x6e, 0x59,
        0x11, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x52, 0x5b,
+       0x00, 0xe2, 0x66, 0x5b,
        0x08, 0x5a, 0xb4, 0x00,
-       0x00, 0xe2, 0x44, 0x5e,
+       0x00, 0xe2, 0x5e, 0x5e,
        0xa8, 0xea, 0x32, 0x00,
-       0x00, 0xe2, 0x56, 0x59,
-       0x80, 0x1a, 0x32, 0x7e,
-       0x00, 0xe2, 0x44, 0x5e,
+       0x00, 0xe2, 0x60, 0x59,
+       0x80, 0x1a, 0x4c, 0x7e,
+       0x00, 0xe2, 0x5e, 0x5e,
        0x80, 0x19, 0x32, 0x00,
-       0x40, 0x5b, 0x38, 0x6e,
-       0x08, 0x5a, 0x38, 0x7e,
+       0x40, 0x5b, 0x52, 0x6e,
+       0x08, 0x5a, 0x52, 0x7e,
        0x20, 0x4d, 0x84, 0x78,
        0x02, 0x84, 0x09, 0x03,
-       0x40, 0x5b, 0x04, 0x7e,
+       0x40, 0x5b, 0x18, 0x7e,
        0xff, 0x90, 0x21, 0x1b,
        0x80, 0xf9, 0xf2, 0x01,
-       0x08, 0x92, 0x63, 0x6b,
+       0x08, 0x92, 0x77, 0x6b,
        0x02, 0xea, 0xb4, 0x04,
        0x01, 0x40, 0xe1, 0x30,
        0x05, 0x41, 0xe3, 0x98,
@@ -1039,138 +1052,138 @@ static struct patch {
        { ahd_patch0_func, 64, 1, 1 },
        { ahd_patch2_func, 67, 1, 2 },
        { ahd_patch0_func, 68, 1, 1 },
-       { ahd_patch4_func, 116, 1, 1 },
-       { ahd_patch2_func, 175, 3, 1 },
-       { ahd_patch1_func, 178, 2, 1 },
-       { ahd_patch5_func, 180, 1, 1 },
-       { ahd_patch2_func, 189, 1, 2 },
-       { ahd_patch0_func, 190, 1, 1 },
-       { ahd_patch6_func, 191, 2, 2 },
-       { ahd_patch0_func, 193, 6, 3 },
-       { ahd_patch2_func, 196, 1, 2 },
-       { ahd_patch0_func, 197, 1, 1 },
-       { ahd_patch2_func, 200, 1, 2 },
-       { ahd_patch0_func, 201, 1, 1 },
-       { ahd_patch3_func, 203, 1, 1 },
-       { ahd_patch7_func, 204, 3, 1 },
-       { ahd_patch3_func, 213, 1, 1 },
-       { ahd_patch5_func, 214, 16, 2 },
-       { ahd_patch0_func, 230, 1, 1 },
-       { ahd_patch8_func, 250, 2, 1 },
-       { ahd_patch1_func, 254, 1, 2 },
-       { ahd_patch0_func, 255, 1, 1 },
-       { ahd_patch7_func, 258, 3, 1 },
-       { ahd_patch1_func, 273, 1, 2 },
-       { ahd_patch0_func, 274, 1, 1 },
-       { ahd_patch1_func, 277, 1, 2 },
-       { ahd_patch0_func, 278, 1, 1 },
-       { ahd_patch2_func, 281, 1, 2 },
-       { ahd_patch0_func, 282, 1, 1 },
-       { ahd_patch9_func, 295, 2, 2 },
-       { ahd_patch0_func, 297, 1, 1 },
-       { ahd_patch1_func, 339, 1, 2 },
-       { ahd_patch0_func, 340, 1, 1 },
-       { ahd_patch2_func, 348, 1, 2 },
-       { ahd_patch0_func, 349, 1, 1 },
-       { ahd_patch2_func, 352, 1, 2 },
-       { ahd_patch0_func, 353, 1, 1 },
-       { ahd_patch1_func, 359, 1, 2 },
-       { ahd_patch0_func, 360, 1, 1 },
-       { ahd_patch1_func, 362, 1, 2 },
+       { ahd_patch4_func, 115, 1, 1 },
+       { ahd_patch2_func, 180, 3, 1 },
+       { ahd_patch1_func, 183, 2, 1 },
+       { ahd_patch5_func, 185, 1, 1 },
+       { ahd_patch2_func, 194, 1, 2 },
+       { ahd_patch0_func, 195, 1, 1 },
+       { ahd_patch6_func, 196, 2, 2 },
+       { ahd_patch0_func, 198, 6, 3 },
+       { ahd_patch2_func, 201, 1, 2 },
+       { ahd_patch0_func, 202, 1, 1 },
+       { ahd_patch2_func, 205, 1, 2 },
+       { ahd_patch0_func, 206, 1, 1 },
+       { ahd_patch3_func, 208, 1, 1 },
+       { ahd_patch7_func, 209, 3, 1 },
+       { ahd_patch3_func, 218, 1, 1 },
+       { ahd_patch5_func, 219, 16, 2 },
+       { ahd_patch0_func, 235, 1, 1 },
+       { ahd_patch8_func, 260, 2, 1 },
+       { ahd_patch1_func, 264, 1, 2 },
+       { ahd_patch0_func, 265, 1, 1 },
+       { ahd_patch7_func, 268, 3, 1 },
+       { ahd_patch1_func, 283, 1, 2 },
+       { ahd_patch0_func, 284, 1, 1 },
+       { ahd_patch1_func, 287, 1, 2 },
+       { ahd_patch0_func, 288, 1, 1 },
+       { ahd_patch2_func, 291, 1, 2 },
+       { ahd_patch0_func, 292, 1, 1 },
+       { ahd_patch9_func, 305, 2, 2 },
+       { ahd_patch0_func, 307, 1, 1 },
+       { ahd_patch1_func, 349, 1, 2 },
+       { ahd_patch0_func, 350, 1, 1 },
+       { ahd_patch2_func, 358, 1, 2 },
+       { ahd_patch0_func, 359, 1, 1 },
+       { ahd_patch2_func, 362, 1, 2 },
        { ahd_patch0_func, 363, 1, 1 },
-       { ahd_patch10_func, 382, 1, 1 },
-       { ahd_patch10_func, 385, 1, 1 },
-       { ahd_patch10_func, 387, 1, 1 },
-       { ahd_patch10_func, 399, 1, 1 },
-       { ahd_patch1_func, 409, 1, 2 },
-       { ahd_patch0_func, 410, 1, 1 },
-       { ahd_patch1_func, 412, 1, 2 },
-       { ahd_patch0_func, 413, 1, 1 },
-       { ahd_patch1_func, 421, 1, 2 },
-       { ahd_patch0_func, 422, 1, 1 },
-       { ahd_patch2_func, 435, 1, 2 },
-       { ahd_patch0_func, 436, 1, 1 },
-       { ahd_patch11_func, 472, 1, 1 },
-       { ahd_patch1_func, 480, 1, 2 },
-       { ahd_patch0_func, 481, 1, 1 },
-       { ahd_patch2_func, 493, 1, 2 },
-       { ahd_patch0_func, 494, 1, 1 },
-       { ahd_patch12_func, 497, 6, 2 },
-       { ahd_patch0_func, 503, 1, 1 },
-       { ahd_patch13_func, 524, 7, 1 },
-       { ahd_patch14_func, 533, 1, 1 },
-       { ahd_patch15_func, 542, 1, 1 },
-       { ahd_patch16_func, 543, 1, 2 },
-       { ahd_patch0_func, 544, 1, 1 },
-       { ahd_patch17_func, 547, 1, 1 },
-       { ahd_patch16_func, 548, 1, 1 },
-       { ahd_patch18_func, 559, 1, 2 },
-       { ahd_patch0_func, 560, 1, 1 },
-       { ahd_patch1_func, 579, 1, 2 },
-       { ahd_patch0_func, 580, 1, 1 },
-       { ahd_patch1_func, 583, 1, 2 },
-       { ahd_patch0_func, 584, 1, 1 },
-       { ahd_patch2_func, 589, 1, 2 },
+       { ahd_patch1_func, 369, 1, 2 },
+       { ahd_patch0_func, 370, 1, 1 },
+       { ahd_patch1_func, 372, 1, 2 },
+       { ahd_patch0_func, 373, 1, 1 },
+       { ahd_patch10_func, 392, 1, 1 },
+       { ahd_patch10_func, 395, 1, 1 },
+       { ahd_patch10_func, 397, 1, 1 },
+       { ahd_patch10_func, 409, 1, 1 },
+       { ahd_patch1_func, 419, 1, 2 },
+       { ahd_patch0_func, 420, 1, 1 },
+       { ahd_patch1_func, 422, 1, 2 },
+       { ahd_patch0_func, 423, 1, 1 },
+       { ahd_patch1_func, 431, 1, 2 },
+       { ahd_patch0_func, 432, 1, 1 },
+       { ahd_patch2_func, 445, 1, 2 },
+       { ahd_patch0_func, 446, 1, 1 },
+       { ahd_patch11_func, 482, 1, 1 },
+       { ahd_patch1_func, 490, 1, 2 },
+       { ahd_patch0_func, 491, 1, 1 },
+       { ahd_patch2_func, 503, 1, 2 },
+       { ahd_patch0_func, 504, 1, 1 },
+       { ahd_patch12_func, 507, 6, 2 },
+       { ahd_patch0_func, 513, 1, 1 },
+       { ahd_patch13_func, 534, 7, 1 },
+       { ahd_patch14_func, 543, 1, 1 },
+       { ahd_patch15_func, 552, 1, 1 },
+       { ahd_patch16_func, 553, 1, 2 },
+       { ahd_patch0_func, 554, 1, 1 },
+       { ahd_patch17_func, 557, 1, 1 },
+       { ahd_patch16_func, 558, 1, 1 },
+       { ahd_patch18_func, 569, 1, 2 },
+       { ahd_patch0_func, 570, 1, 1 },
+       { ahd_patch1_func, 589, 1, 2 },
        { ahd_patch0_func, 590, 1, 1 },
-       { ahd_patch2_func, 594, 1, 2 },
-       { ahd_patch0_func, 595, 1, 1 },
-       { ahd_patch1_func, 596, 1, 2 },
-       { ahd_patch0_func, 597, 1, 1 },
-       { ahd_patch2_func, 608, 1, 2 },
-       { ahd_patch0_func, 609, 1, 1 },
-       { ahd_patch19_func, 613, 1, 1 },
-       { ahd_patch20_func, 618, 1, 1 },
-       { ahd_patch21_func, 619, 2, 1 },
-       { ahd_patch20_func, 623, 1, 2 },
-       { ahd_patch0_func, 624, 1, 1 },
-       { ahd_patch2_func, 627, 1, 2 },
-       { ahd_patch0_func, 628, 1, 1 },
-       { ahd_patch2_func, 643, 1, 2 },
-       { ahd_patch0_func, 644, 1, 1 },
-       { ahd_patch13_func, 645, 14, 1 },
-       { ahd_patch1_func, 663, 1, 2 },
-       { ahd_patch0_func, 664, 1, 1 },
-       { ahd_patch13_func, 665, 1, 1 },
-       { ahd_patch1_func, 677, 1, 2 },
-       { ahd_patch0_func, 678, 1, 1 },
-       { ahd_patch1_func, 685, 1, 2 },
-       { ahd_patch0_func, 686, 1, 1 },
-       { ahd_patch19_func, 709, 1, 1 },
-       { ahd_patch19_func, 747, 1, 1 },
-       { ahd_patch1_func, 758, 1, 2 },
-       { ahd_patch0_func, 759, 1, 1 },
-       { ahd_patch1_func, 776, 1, 2 },
-       { ahd_patch0_func, 777, 1, 1 },
-       { ahd_patch1_func, 779, 1, 2 },
-       { ahd_patch0_func, 780, 1, 1 },
-       { ahd_patch1_func, 783, 1, 2 },
-       { ahd_patch0_func, 784, 1, 1 },
-       { ahd_patch22_func, 786, 1, 2 },
-       { ahd_patch0_func, 787, 2, 1 },
-       { ahd_patch23_func, 790, 4, 2 },
-       { ahd_patch0_func, 794, 1, 1 },
-       { ahd_patch23_func, 802, 11, 1 }
+       { ahd_patch1_func, 593, 1, 2 },
+       { ahd_patch0_func, 594, 1, 1 },
+       { ahd_patch2_func, 599, 1, 2 },
+       { ahd_patch0_func, 600, 1, 1 },
+       { ahd_patch2_func, 604, 1, 2 },
+       { ahd_patch0_func, 605, 1, 1 },
+       { ahd_patch1_func, 606, 1, 2 },
+       { ahd_patch0_func, 607, 1, 1 },
+       { ahd_patch2_func, 618, 1, 2 },
+       { ahd_patch0_func, 619, 1, 1 },
+       { ahd_patch19_func, 623, 1, 1 },
+       { ahd_patch20_func, 628, 1, 1 },
+       { ahd_patch21_func, 629, 2, 1 },
+       { ahd_patch20_func, 633, 1, 2 },
+       { ahd_patch0_func, 634, 1, 1 },
+       { ahd_patch2_func, 637, 1, 2 },
+       { ahd_patch0_func, 638, 1, 1 },
+       { ahd_patch2_func, 653, 1, 2 },
+       { ahd_patch0_func, 654, 1, 1 },
+       { ahd_patch13_func, 655, 14, 1 },
+       { ahd_patch1_func, 673, 1, 2 },
+       { ahd_patch0_func, 674, 1, 1 },
+       { ahd_patch13_func, 675, 1, 1 },
+       { ahd_patch1_func, 687, 1, 2 },
+       { ahd_patch0_func, 688, 1, 1 },
+       { ahd_patch1_func, 695, 1, 2 },
+       { ahd_patch0_func, 696, 1, 1 },
+       { ahd_patch19_func, 719, 1, 1 },
+       { ahd_patch19_func, 757, 1, 1 },
+       { ahd_patch1_func, 768, 1, 2 },
+       { ahd_patch0_func, 769, 1, 1 },
+       { ahd_patch7_func, 785, 3, 1 },
+       { ahd_patch1_func, 789, 1, 2 },
+       { ahd_patch0_func, 790, 1, 1 },
+       { ahd_patch1_func, 792, 1, 2 },
+       { ahd_patch0_func, 793, 1, 1 },
+       { ahd_patch1_func, 796, 1, 2 },
+       { ahd_patch0_func, 797, 1, 1 },
+       { ahd_patch22_func, 799, 1, 2 },
+       { ahd_patch0_func, 800, 2, 1 },
+       { ahd_patch23_func, 803, 4, 2 },
+       { ahd_patch0_func, 807, 1, 1 },
+       { ahd_patch23_func, 815, 11, 1 }
 };
 
 static struct cs {
        uint16_t        begin;
        uint16_t        end;
 } critical_sections[] = {
-       { 17, 28 },
-       { 29, 30 },
+       { 17, 30 },
        { 47, 58 },
        { 61, 63 },
        { 65, 66 },
        { 72, 92 },
-       { 110, 137 },
-       { 138, 175 },
-       { 180, 188 },
-       { 213, 264 },
-       { 425, 433 },
-       { 443, 445 },
-       { 448, 457 },
-       { 709, 739 },
-       { 749, 753 }
+       { 110, 142 },
+       { 143, 180 },
+       { 185, 193 },
+       { 218, 274 },
+       { 435, 443 },
+       { 453, 455 },
+       { 458, 467 },
+       { 719, 749 },
+       { 759, 763 }
 };
 
 static const int num_critical_sections = sizeof(critical_sections)
index f936b691232f90d4d020998d8a3420508b36cc85..924102720b141fe969f0891924fa1384e8269a2f 100644 (file)
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#22 $
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#23 $
  *
  * $FreeBSD$
  */
@@ -609,10 +609,10 @@ output_listing(char *ifilename)
 
                while (line < cur_instr->srcline) {
                        fgets(buf, sizeof(buf), ifile);
-                               fprintf(listfile, "\t\t%s", buf);
+                               fprintf(listfile, "             \t%s", buf);
                                line++;
                }
-               fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
+               fprintf(listfile, "%04x %02x%02x%02x%02x", instrptr,
 #ifdef __LITTLE_ENDIAN
                        cur_instr->format.bytes[0],
                        cur_instr->format.bytes[1],
@@ -624,14 +624,23 @@ output_listing(char *ifilename)
                        cur_instr->format.bytes[1],
                        cur_instr->format.bytes[0]);
 #endif
-               fgets(buf, sizeof(buf), ifile);
-               fprintf(listfile, "\t%s", buf);
-               line++;
+               /*
+                * Macro expansions can cause several instructions
+                * to be output for a single source line.  Only
+                * advance the line once in these cases.
+                */
+               if (line == cur_instr->srcline) {
+                       fgets(buf, sizeof(buf), ifile);
+                       fprintf(listfile, "\t%s", buf);
+                       line++;
+               } else {
+                       fprintf(listfile, "\n");
+               }
                instrptr++;
        }
        /* Dump the remainder of the file */
        while(fgets(buf, sizeof(buf), ifile) != NULL)
-               fprintf(listfile, "\t\t%s", buf);
+               fprintf(listfile, "             %s", buf);
 
        fclose(ifile);
 }
index 67e046d966254929af3e88849bb7c8baa88fcaf5..c328596def3c557f25c4b6bc88ec3bba94bfa3d8 100644 (file)
@@ -38,7 +38,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#29 $
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#30 $
  *
  * $FreeBSD$
  */
@@ -157,6 +157,8 @@ static int  is_download_const(expression_t *immed);
 
 %token T_END_CS
 
+%token T_PAD_PAGE
+
 %token T_FIELD
 
 %token T_ENUM
@@ -189,6 +191,10 @@ static int  is_download_const(expression_t *immed);
 
 %token <value> T_OR
 
+/* 16 bit extensions */
+%token <value> T_OR16 T_AND16 T_XOR16 T_ADD16
+%token <value> T_ADC16 T_MVI16 T_TEST16 T_CMP16 T_CMPXCHG
+
 %token T_RET
 
 %token T_NOP
@@ -207,7 +213,7 @@ static int  is_download_const(expression_t *immed);
 
 %type <expression> expression immediate immediate_or_a
 
-%type <value> export ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
+%type <value> export ret f1_opcode f2_opcode f4_opcode jmp_jc_jnc_call jz_jnz je_jne
 
 %type <value> mode_value mode_list macro_arglist
 
@@ -1304,6 +1310,15 @@ f2_opcode:
 |      T_ROR { $$ = AIC_OP_ROR; }
 ;
 
+f4_opcode:
+       T_OR16  { $$ = AIC_OP_OR16; }
+|      T_AND16 { $$ = AIC_OP_AND16; }
+|      T_XOR16 { $$ = AIC_OP_XOR16; }
+|      T_ADD16 { $$ = AIC_OP_ADD16; }
+|      T_ADC16 { $$ = AIC_OP_ADC16; }
+|      T_MVI16 { $$ = AIC_OP_MVI16; }
+;
+
 code:
        f2_opcode destination ',' expression opt_source ret ';'
        {
index e64f802bbaaa165884bafc117082eab38c23f701..9df9e2ce3538e27a711e7ad6ee4fc5aa595ccdf3 100644 (file)
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_insformat.h#11 $
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_insformat.h#12 $
  *
  * $FreeBSD$
  */
 
 #include <asm/byteorder.h>
 
+/* 8bit ALU logic operations */
 struct ins_format1 {
 #ifdef __LITTLE_ENDIAN
        uint32_t        immediate       : 8,
@@ -62,6 +63,7 @@ struct ins_format1 {
 #endif
 };
 
+/* 8bit ALU shift/rotate operations */
 struct ins_format2 {
 #ifdef __LITTLE_ENDIAN
        uint32_t        shift_control   : 8,
@@ -80,6 +82,7 @@ struct ins_format2 {
 #endif
 };
 
+/* 8bit branch control operations */
 struct ins_format3 {
 #ifdef __LITTLE_ENDIAN
        uint32_t        immediate       : 8,
@@ -96,10 +99,68 @@ struct ins_format3 {
 #endif
 };
 
+/* 16bit ALU logic operations */
+struct ins_format4 {
+#ifdef __LITTLE_ENDIAN
+       uint32_t        opcode_ext      : 8,
+                       source          : 9,
+                       destination     : 9,
+                       ret             : 1,
+                       opcode          : 4,
+                       parity          : 1;
+#else
+       uint32_t        parity          : 1,
+                       opcode          : 4,
+                       ret             : 1,
+                       destination     : 9,
+                       source          : 9,
+                       opcode_ext      : 8;
+#endif
+};
+
+/* 16bit branch control operations */
+struct ins_format5 {
+#ifdef __LITTLE_ENDIAN
+       uint32_t        opcode_ext      : 8,
+                       source          : 9,
+                       address         : 10,
+                       opcode          : 4,
+                       parity          : 1;
+#else
+       uint32_t        parity          : 1,
+                       opcode          : 4,
+                       address         : 10,
+                       source          : 9,
+                       opcode_ext      : 8;
+#endif
+};
+
+/*  Far branch operations */
+struct ins_format6 {
+#ifdef __LITTLE_ENDIAN
+       uint32_t        page            : 3,
+                       opcode_ext      : 5,
+                       source          : 9,
+                       address         : 10,
+                       opcode          : 4,
+                       parity          : 1;
+#else
+       uint32_t        parity          : 1,
+                       opcode          : 4,
+                       address         : 10,
+                       source          : 9,
+                       opcode_ext      : 5,
+                       page            : 3;
+#endif
+};
+
 union ins_formats {
                struct ins_format1 format1;
                struct ins_format2 format2;
                struct ins_format3 format3;
+               struct ins_format4 format4;
+               struct ins_format5 format5;
+               struct ins_format6 format6;
                uint8_t            bytes[4];
                uint32_t           integer;
 };
@@ -118,6 +179,8 @@ struct instruction {
 #define        AIC_OP_ROL      0x5
 #define        AIC_OP_BMOV     0x6
 
+#define        AIC_OP_MVI16    0x7
+
 #define        AIC_OP_JMP      0x8
 #define AIC_OP_JC      0x9
 #define AIC_OP_JNC     0xa
@@ -131,3 +194,26 @@ struct instruction {
 #define        AIC_OP_SHL      0x10
 #define        AIC_OP_SHR      0x20
 #define        AIC_OP_ROR      0x30
+
+/* 16bit Ops. Low byte main opcode.  High byte extended opcode. */ 
+#define        AIC_OP_OR16     0x8005
+#define        AIC_OP_AND16    0x8105
+#define        AIC_OP_XOR16    0x8205
+#define        AIC_OP_ADD16    0x8305
+#define        AIC_OP_ADC16    0x8405
+#define AIC_OP_JNE16   0x8805
+#define AIC_OP_JNZ16   0x8905
+#define AIC_OP_JE16    0x8C05
+#define AIC_OP_JZ16    0x8B05
+#define AIC_OP_JMP16   0x9005
+#define AIC_OP_JC16    0x9105
+#define AIC_OP_JNC16   0x9205
+#define AIC_OP_CALL16  0x9305
+#define AIC_OP_CALL16  0x9305
+
+/* Page extension is low three bits of second opcode byte. */
+#define AIC_OP_JMPF    0xA005
+#define AIC_OP_CALLF   0xB005
+#define AIC_OP_JCF     0xC005
+#define AIC_OP_JNCF    0xD005
+#define AIC_OP_CMPXCHG 0xE005
index 45c0b233d0bc239ba99acbf39b8765f7e8bce7da..7c3983f868a9a8c171d9d165438abf5f187be6fd 100644 (file)
@@ -38,7 +38,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#19 $
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#20 $
  *
  * $FreeBSD$
  */
@@ -132,7 +132,7 @@ if[ \t]*\(          {
                                                *string_buf_ptr++ = *yptr++;
                                }
                        }
-
+else                   { return T_ELSE; }
 VERSION                        { return T_VERSION; }
 PREFIX                 { return T_PREFIX; }
 PATCH_ARG_LIST         { return T_PATCH_ARG_LIST; }
@@ -173,10 +173,6 @@ RW|RO|WO           {
                                        yylval.value = WO;
                                 return T_MODE;
                        }
-BEGIN_CRITICAL         { return T_BEGIN_CS; }
-END_CRITICAL           { return T_END_CS; }
-SET_SRC_MODE           { return T_SET_SRC_MODE; }
-SET_DST_MODE           { return T_SET_DST_MODE; }
 field                  { return T_FIELD; }
 enum                   { return T_ENUM; }
 mask                   { return T_MASK; }
@@ -192,6 +188,13 @@ none                       { return T_NONE; }
 sindex                 { return T_SINDEX; }
 A                      { return T_A; }
 
+       /* Instruction Formatting */
+PAD_PAGE               { return T_PAD_PAGE; }
+BEGIN_CRITICAL         { return T_BEGIN_CS; }
+END_CRITICAL           { return T_END_CS; }
+SET_SRC_MODE           { return T_SET_SRC_MODE; }
+SET_DST_MODE           { return T_SET_DST_MODE; }
+
        /* Opcodes */
 shl                    { return T_SHL; }
 shr                    { return T_SHR; }
@@ -223,7 +226,17 @@ and                        { return T_AND; }
 or                     { return T_OR;  }
 ret                    { return T_RET; }
 nop                    { return T_NOP; }
-else                   { return T_ELSE; }
+
+       /* ARP2 16bit extensions */
+or16                   { return T_OR16; }
+and16                  { return T_AND16; }
+xor16                  { return T_XOR16; }
+add16                  { return T_ADD16; }
+adc16                  { return T_ADC16; }
+mvi16                  { return T_MVI16; }
+test16                 { return T_TEST16; }
+cmp16                  { return T_CMP16; }
+cmpxchg                        { return T_CMPXCHG; }
 
        /* Allowed Symbols */
 \<\<                   { return T_EXPR_LSHIFT; }
index c8a32cf47d738fba4e991d1c2f37e09c6a5b08c2..cbf825263f3b4a89512cf3ea18afc7aa74f92571 100644 (file)
@@ -246,6 +246,7 @@ struct ScsiReqBlk {
         * total_xfer_length in xferred. These values are restored in
         * pci_unmap_srb_sense. This is the only place xferred is used.
         */
+       unsigned char *virt_addr_req;   /* Saved virtual address of the request buffer */
        u32 xferred;                    /* Saved copy of total_xfer_length */
 
        u16 state;
@@ -2017,7 +2018,7 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
        sg_verify_length(srb);
 
        /* we need the corresponding virtual address */
-       if (!segment) {
+       if (!segment || (srb->flag & AUTO_REQSENSE)) {
                srb->virt_addr += xferred;
                return;
        }
@@ -3318,6 +3319,7 @@ static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
            srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address;
        srb->segment_x[0].length =
            srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length;
+       srb->virt_addr = srb->virt_addr_req;
 }
 
 
@@ -3711,6 +3713,8 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
        srb->xferred = srb->total_xfer_length;
        /* srb->segment_x : a one entry of S/G list table */
        srb->total_xfer_length = sizeof(cmd->sense_buffer);
+       srb->virt_addr_req = srb->virt_addr;
+       srb->virt_addr = cmd->sense_buffer;
        srb->segment_x[0].length = sizeof(cmd->sense_buffer);
        /* Map sense buffer */
        srb->segment_x[0].address =
index 822b9fa706f385f789d6cbbe125b971d586e4ec1..eaefeddb2b4ad48aa57e124a6eef2dfefeaf472a 100644 (file)
@@ -87,7 +87,7 @@ static int max_channel = 3;
 static int init_timeout = 5;
 static int max_requests = 50;
 
-#define IBMVSCSI_VERSION "1.5.7"
+#define IBMVSCSI_VERSION "1.5.8"
 
 MODULE_DESCRIPTION("IBM Virtual SCSI");
 MODULE_AUTHOR("Dave Boutcher");
@@ -534,7 +534,6 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
 static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
                                   struct ibmvscsi_host_data *hostdata)
 {
-       struct scsi_cmnd *cmnd;
        u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
        int rc;
 
@@ -544,19 +543,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
         * can handle more requests (can_queue) when we actually can't
         */
        if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) &&
-           (atomic_dec_if_positive(&hostdata->request_limit) < 0)) {
-               /* See if the adapter is disabled */
-               if (atomic_read(&hostdata->request_limit) < 0)
-                       goto send_error;
-       
-               printk(KERN_WARNING 
-                      "ibmvscsi: Warning, request_limit exceeded\n");
-               unmap_cmd_data(&evt_struct->iu.srp.cmd,
-                              evt_struct,
-                              hostdata->dev);
-               free_event_struct(&hostdata->pool, evt_struct);
-               return SCSI_MLQUEUE_HOST_BUSY;
-       }
+           (atomic_dec_if_positive(&hostdata->request_limit) < 0))
+               goto send_error;
 
        /* Copy the IU into the transfer area */
        *evt_struct->xfer_iu = evt_struct->iu;
@@ -572,7 +560,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
             ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
                list_del(&evt_struct->list);
 
-               printk(KERN_ERR "ibmvscsi: failed to send event struct rc %d\n",
+               printk(KERN_ERR "ibmvscsi: send error %d\n",
                       rc);
                goto send_error;
        }
@@ -582,14 +570,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
  send_error:
        unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
 
-       if ((cmnd = evt_struct->cmnd) != NULL) {
-               cmnd->result = DID_ERROR << 16;
-               evt_struct->cmnd_done(cmnd);
-       } else if (evt_struct->done)
-               evt_struct->done(evt_struct);
-       
        free_event_struct(&hostdata->pool, evt_struct);
-       return 0;
+       return SCSI_MLQUEUE_HOST_BUSY;
 }
 
 /**
@@ -802,7 +784,8 @@ static void login_rsp(struct srp_event_struct *evt_struct)
        case SRP_LOGIN_RSP_TYPE:        /* it worked! */
                break;
        case SRP_LOGIN_REJ_TYPE:        /* refused! */
-               printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REQ rejected\n");
+               printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REJ reason %u\n",
+                      evt_struct->xfer_iu->srp.login_rej.reason);
                /* Login failed.  */
                atomic_set(&hostdata->request_limit, -1);
                return;
@@ -834,6 +817,9 @@ static void login_rsp(struct srp_event_struct *evt_struct)
                return;
        }
 
+       /* If we had any pending I/Os, kick them */
+       scsi_unblock_requests(hostdata->host);
+
        send_mad_adapter_info(hostdata);
        return;
 }
@@ -862,6 +848,7 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
                          init_timeout * HZ);
 
        login = &evt_struct->iu.srp.login_req;
+       memset(login, 0x00, sizeof(struct srp_login_req));
        login->type = SRP_LOGIN_REQ_TYPE;
        login->max_requested_initiator_to_target_iulen = sizeof(union srp_iu);
        login->required_buffer_formats = 0x0006;
@@ -1122,7 +1109,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
  * purge_requests: Our virtual adapter just shut down.  purge any sent requests
  * @hostdata:    the adapter
  */
-static void purge_requests(struct ibmvscsi_host_data *hostdata)
+static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
 {
        struct srp_event_struct *tmp_evt, *pos;
        unsigned long flags;
@@ -1131,7 +1118,7 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata)
        list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
                list_del(&tmp_evt->list);
                if (tmp_evt->cmnd) {
-                       tmp_evt->cmnd->result = (DID_ERROR << 16);
+                       tmp_evt->cmnd->result = (error_code << 16);
                        unmap_cmd_data(&tmp_evt->iu.srp.cmd, 
                                       tmp_evt, 
                                       tmp_evt->hostdata->dev);
@@ -1186,12 +1173,30 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                        printk(KERN_ERR "ibmvscsi: unknown crq message type\n");
                }
                return;
-       case 0xFF:              /* Hypervisor telling us the connection is closed */
-               printk(KERN_INFO "ibmvscsi: Virtual adapter failed!\n");
+       case 0xFF:      /* Hypervisor telling us the connection is closed */
+               scsi_block_requests(hostdata->host);
+               if (crq->format == 0x06) {
+                       /* We need to re-setup the interpartition connection */
+                       printk(KERN_INFO
+                              "ibmvscsi: Re-enabling adapter!\n");
+                       purge_requests(hostdata, DID_REQUEUE);
+                       if (ibmvscsi_reenable_crq_queue(&hostdata->queue,
+                                                       hostdata) == 0)
+                               if (ibmvscsi_send_crq(hostdata,
+                                                     0xC001000000000000LL, 0))
+                                       printk(KERN_ERR
+                                              "ibmvscsi: transmit error after"
+                                              " enable\n");
+               } else {
+                       printk(KERN_INFO
+                              "ibmvscsi: Virtual adapter failed rc %d!\n",
+                              crq->format);
 
-               atomic_set(&hostdata->request_limit, -1);
-               purge_requests(hostdata);
-               ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
+                       atomic_set(&hostdata->request_limit, -1);
+                       purge_requests(hostdata, DID_ERROR);
+                       ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
+               }
+               scsi_unblock_requests(hostdata->host);
                return;
        case 0x80:              /* real payload */
                break;
index 5b0edd1f19213e3d97c173c4659659e5c63b6891..4550d71e474475bec487075c96d1c7aed7df8d88 100644 (file)
@@ -103,6 +103,9 @@ void ibmvscsi_release_crq_queue(struct crq_queue *queue,
 int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
                              struct ibmvscsi_host_data *hostdata);
 
+int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
+                               struct ibmvscsi_host_data *hostdata);
+
 void ibmvscsi_handle_crq(struct viosrp_crq *crq,
                         struct ibmvscsi_host_data *hostdata);
 int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
index ce15d9e3962114f5f49d84df48de41814291ce79..7eed0b098171f6b37670ebe3db4b24689cfa68ad 100644 (file)
@@ -123,6 +123,19 @@ int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
        return 0;
 }
 
+/**
+ * reenable_crq_queue: - reenables a crq after a failure
+ * @queue:     crq_queue to initialize and register
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+ * no-op for iSeries
+ */
+int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
+                               struct ibmvscsi_host_data *hostdata)
+{
+       return 0;
+}
+
 /**
  * ibmvscsi_send_crq: - Send a CRQ
  * @hostdata:  the adapter
index 75db2f5c545e999d2b06b313560bf3610447bdd5..f47dd87c05e7566bcb58e054fbcfcbd7eeb06613 100644 (file)
@@ -280,6 +280,28 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
        return -1;
 }
 
+/**
+ * reenable_crq_queue: - reenables a crq after
+ * @queue:     crq_queue to initialize and register
+ * @hostdata:  ibmvscsi_host_data of host
+ *
+ */
+int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
+                                struct ibmvscsi_host_data *hostdata)
+{
+       int rc;
+       struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+       /* Re-enable the CRQ */
+       do {
+               rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
+       } while ((rc == H_InProgress) || (rc == H_Busy) || (H_isLongBusy(rc)));
+
+       if (rc)
+               printk(KERN_ERR "ibmvscsi: Error %d enabling adapter\n", rc);
+       return rc;
+}
+
 /**
  * reset_crq_queue: - resets a crq after a failure
  * @queue:     crq_queue to initialize and register
index e5e1ca44e1eea831e17814c84d81db91b62be2cf..86c546164da9f1dc78b98d4f2982e9b45d602d0c 100644 (file)
@@ -3499,6 +3499,7 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
        int device_error;
        uint32_t transfer_len;
        IPS_DCDB_TABLE_TAPE *tapeDCDB;
+       IPS_SCSI_INQ_DATA inquiryData;
 
        METHOD_TRACE("ips_map_status", 1);
 
@@ -3557,13 +3558,13 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
                                errcode = DID_OK;
 
                                /* Restrict access to physical DASD */
-                               if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
-                                   ((((char *) scb->scsi_cmd->
-                                      buffer)[0] & 0x1f) == TYPE_DISK)) {
-                                       /* underflow -- no error               */
-                                       /* restrict access to physical DASD    */
-                                       errcode = DID_TIME_OUT;
-                                       break;
+                               if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
+                                   ips_scmd_buf_read(scb->scsi_cmd, 
+                                      &inquiryData, sizeof (inquiryData));
+                                   if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) {
+                                       errcode = DID_TIME_OUT;
+                                       break;
+                                   }
                                }
                        } else
                                errcode = DID_ERROR;
@@ -4135,6 +4136,7 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
        uint8_t basic_status;
        uint8_t ext_status;
        int errcode;
+       IPS_SCSI_INQ_DATA inquiryData;
 
        METHOD_TRACE("ips_chkstatus", 1);
 
@@ -4255,11 +4257,11 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
                        scb->scsi_cmd->result = errcode << 16;
                } else {        /* bus == 0 */
                        /* restrict access to physical drives */
-                       if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
-                           ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) ==
-                            TYPE_DISK)) {
-
-                               scb->scsi_cmd->result = DID_TIME_OUT << 16;
+                       if (scb->scsi_cmd->cmnd[0] == INQUIRY) { 
+                           ips_scmd_buf_read(scb->scsi_cmd, 
+                                  &inquiryData, sizeof (inquiryData));
+                           if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) 
+                               scb->scsi_cmd->result = DID_TIME_OUT << 16;
                        }
                }               /* else */
        } else {                /* recovered error / success */
@@ -5012,7 +5014,7 @@ ips_init_copperhead(ips_ha_t * ha)
                                break;
 
                        /* Delay for 1 Second */
-                       MDELAY(IPS_ONE_SEC);
+                       msleep(IPS_ONE_SEC);
                }
 
                if (j >= 45)
@@ -5038,7 +5040,7 @@ ips_init_copperhead(ips_ha_t * ha)
                                break;
 
                        /* Delay for 1 Second */
-                       MDELAY(IPS_ONE_SEC);
+                       msleep(IPS_ONE_SEC);
                }
 
                if (j >= 240)
@@ -5056,7 +5058,7 @@ ips_init_copperhead(ips_ha_t * ha)
                        break;
 
                /* Delay for 1 Second */
-               MDELAY(IPS_ONE_SEC);
+               msleep(IPS_ONE_SEC);
        }
 
        if (i >= 240)
@@ -5106,7 +5108,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
                                break;
 
                        /* Delay for 1 Second */
-                       MDELAY(IPS_ONE_SEC);
+                       msleep(IPS_ONE_SEC);
                }
 
                if (j >= 45)
@@ -5132,7 +5134,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
                                break;
 
                        /* Delay for 1 Second */
-                       MDELAY(IPS_ONE_SEC);
+                       msleep(IPS_ONE_SEC);
                }
 
                if (j >= 240)
@@ -5150,7 +5152,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
                        break;
 
                /* Delay for 1 Second */
-               MDELAY(IPS_ONE_SEC);
+               msleep(IPS_ONE_SEC);
        }
 
        if (i >= 240)
@@ -5202,7 +5204,7 @@ ips_init_morpheus(ips_ha_t * ha)
                        break;
 
                /* Delay for 1 Second */
-               MDELAY(IPS_ONE_SEC);
+               msleep(IPS_ONE_SEC);
        }
 
        if (i >= 45) {
@@ -5228,7 +5230,7 @@ ips_init_morpheus(ips_ha_t * ha)
                        if (Post != 0x4F00)
                                break;
                        /* Delay for 1 Second */
-                       MDELAY(IPS_ONE_SEC);
+                       msleep(IPS_ONE_SEC);
                }
 
                if (i >= 120) {
@@ -5258,7 +5260,7 @@ ips_init_morpheus(ips_ha_t * ha)
                        break;
 
                /* Delay for 1 Second */
-               MDELAY(IPS_ONE_SEC);
+               msleep(IPS_ONE_SEC);
        }
 
        if (i >= 240) {
@@ -5318,12 +5320,12 @@ ips_reset_copperhead(ips_ha_t * ha)
                outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);
 
                /* Delay for 1 Second */
-               MDELAY(IPS_ONE_SEC);
+               msleep(IPS_ONE_SEC);
 
                outb(0, ha->io_addr + IPS_REG_SCPR);
 
                /* Delay for 1 Second */
-               MDELAY(IPS_ONE_SEC);
+               msleep(IPS_ONE_SEC);
 
                if ((*ha->func.init) (ha))
                        break;
@@ -5363,12 +5365,12 @@ ips_reset_copperhead_memio(ips_ha_t * ha)
                writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
 
                /* Delay for 1 Second */
-               MDELAY(IPS_ONE_SEC);
+               msleep(IPS_ONE_SEC);
 
                writeb(0, ha->mem_ptr + IPS_REG_SCPR);
 
                /* Delay for 1 Second */
-               MDELAY(IPS_ONE_SEC);
+               msleep(IPS_ONE_SEC);
 
                if ((*ha->func.init) (ha))
                        break;
@@ -5409,7 +5411,7 @@ ips_reset_morpheus(ips_ha_t * ha)
                writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
 
                /* Delay for 5 Seconds */
-               MDELAY(5 * IPS_ONE_SEC);
+               msleep(5 * IPS_ONE_SEC);
 
                /* Do a PCI config read to wait for adapter */
                pci_read_config_byte(ha->pcidev, 4, &junk);
index cfbceb5047183e3096bb494bc3e2419c8956cd93..07b1e7cc61dfcbc0ab5ce762be6d83ecb4f1f1db 100644 (file)
@@ -1700,6 +1700,31 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
        return sizeof(def_rw_recovery_mpage);
 }
 
+/*
+ * We can turn this into a real blacklist if it's needed, for now just
+ * blacklist any Maxtor BANC1G10 revision firmware
+ */
+static int ata_dev_supports_fua(u16 *id)
+{
+       unsigned char model[41], fw[9];
+
+       if (!ata_id_has_fua(id))
+               return 0;
+
+       model[40] = '\0';
+       fw[8] = '\0';
+
+       ata_dev_id_string(id, model, ATA_ID_PROD_OFS, sizeof(model) - 1);
+       ata_dev_id_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw) - 1);
+
+       if (strncmp(model, "Maxtor", 6))
+               return 1;
+       if (strncmp(fw, "BANC1G10", 8))
+               return 1;
+
+       return 0; /* blacklisted */
+}
+
 /**
  *     ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
  *     @args: device IDENTIFY data / SCSI command of interest.
@@ -1797,7 +1822,7 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
                return 0;
 
        dpofua = 0;
-       if (ata_id_has_fua(args->id) && dev->flags & ATA_DFLAG_LBA48 &&
+       if (ata_dev_supports_fua(args->id) && dev->flags & ATA_DFLAG_LBA48 &&
            (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
                dpofua = 1 << 4;
 
index 511ed52a580747be705be11e3f1d9dce325af7c8..a487f414960e5e9a6553c7c1b7dc7fe2042253c2 100644 (file)
@@ -10,7 +10,7 @@
  *        2 of the License, or (at your option) any later version.
  *
  * FILE                : megaraid_sas.c
- * Version     : v00.00.02.00-rc4
+ * Version     : v00.00.02.02
  *
  * Authors:
  *     Sreenivas Bagalkote     <Sreenivas.Bagalkote@lsil.com>
@@ -55,13 +55,13 @@ static struct pci_device_id megasas_pci_table[] = {
 
        {
         PCI_VENDOR_ID_LSI_LOGIC,
-        PCI_DEVICE_ID_LSI_SAS1064R,
+        PCI_DEVICE_ID_LSI_SAS1064R, // xscale IOP
         PCI_ANY_ID,
         PCI_ANY_ID,
         },
        {
         PCI_VENDOR_ID_DELL,
-        PCI_DEVICE_ID_DELL_PERC5,
+        PCI_DEVICE_ID_DELL_PERC5, // xscale IOP
         PCI_ANY_ID,
         PCI_ANY_ID,
         },
@@ -119,12 +119,18 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
        spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
 }
 
+
+/**
+*      The following functions are defined for xscale 
+*      (deviceid : 1064R, PERC5) controllers
+*/
+
 /**
- * megasas_enable_intr -       Enables interrupts
+ * megasas_enable_intr_xscale -        Enables interrupts
  * @regs:                      MFI register set
  */
 static inline void
-megasas_enable_intr(struct megasas_register_set __iomem * regs)
+megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
 {
        writel(1, &(regs)->outbound_intr_mask);
 
@@ -132,6 +138,66 @@ megasas_enable_intr(struct megasas_register_set __iomem * regs)
        readl(&regs->outbound_intr_mask);
 }
 
+/**
+ * megasas_read_fw_status_reg_xscale - returns the current FW status value
+ * @regs:                      MFI register set
+ */
+static u32
+megasas_read_fw_status_reg_xscale(struct megasas_register_set __iomem * regs)
+{
+       return readl(&(regs)->outbound_msg_0);
+}
+/**
+ * megasas_clear_interrupt_xscale -    Check & clear interrupt
+ * @regs:                              MFI register set
+ */
+static int 
+megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
+{
+       u32 status;
+       /*
+        * Check if it is our interrupt
+        */
+       status = readl(&regs->outbound_intr_status);
+
+       if (!(status & MFI_OB_INTR_STATUS_MASK)) {
+               return 1;
+       }
+
+       /*
+        * Clear the interrupt by writing back the same value
+        */
+       writel(status, &regs->outbound_intr_status);
+
+       return 0;
+}
+
+/**
+ * megasas_fire_cmd_xscale -   Sends command to the FW
+ * @frame_phys_addr :          Physical address of cmd
+ * @frame_count :              Number of frames for the command
+ * @regs :                     MFI register set
+ */
+static inline void 
+megasas_fire_cmd_xscale(dma_addr_t frame_phys_addr,u32 frame_count, struct megasas_register_set __iomem *regs)
+{
+       writel((frame_phys_addr >> 3)|(frame_count),
+              &(regs)->inbound_queue_port);
+}
+
+static struct megasas_instance_template megasas_instance_template_xscale = {
+
+       .fire_cmd = megasas_fire_cmd_xscale,
+       .enable_intr = megasas_enable_intr_xscale,
+       .clear_intr = megasas_clear_intr_xscale,
+       .read_fw_status_reg = megasas_read_fw_status_reg_xscale,
+};
+
+/**
+*      This is the end of set of functions & definitions specific 
+*      to xscale (deviceid : 1064R, PERC5) controllers
+*/
+
 /**
  * megasas_disable_intr -      Disables interrupts
  * @regs:                      MFI register set
@@ -139,7 +205,7 @@ megasas_enable_intr(struct megasas_register_set __iomem * regs)
 static inline void
 megasas_disable_intr(struct megasas_register_set __iomem * regs)
 {
-       u32 mask = readl(&regs->outbound_intr_mask) & (~0x00000001);
+       u32 mask = 0x1f; 
        writel(mask, &regs->outbound_intr_mask);
 
        /* Dummy readl to force pci flush */
@@ -167,8 +233,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
        /*
         * Issue the frame using inbound queue port
         */
-       writel(cmd->frame_phys_addr >> 3,
-              &instance->reg_set->inbound_queue_port);
+       instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
 
        /*
         * Wait for cmd_status to change
@@ -198,8 +263,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
 {
        cmd->cmd_status = ENODATA;
 
-       writel(cmd->frame_phys_addr >> 3,
-              &instance->reg_set->inbound_queue_port);
+       instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
 
        wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));
 
@@ -242,8 +306,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
        cmd->sync_cmd = 1;
        cmd->cmd_status = 0xFF;
 
-       writel(cmd->frame_phys_addr >> 3,
-              &instance->reg_set->inbound_queue_port);
+       instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
 
        /*
         * Wait for this cmd to complete
@@ -558,112 +621,29 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
 }
 
 /**
- * megasas_build_cmd - Prepares a command packet
- * @instance:          Adapter soft state
- * @scp:               SCSI command
- * @frame_count:       [OUT] Number of frames used to prepare this command
+ * megasas_is_ldio -           Checks if the cmd is for logical drive
+ * @scmd:                      SCSI command
+ *     
+ * Called by megasas_queue_command to find out if the command to be queued
+ * is a logical drive command  
  */
-static struct megasas_cmd *megasas_build_cmd(struct megasas_instance
-                                                   *instance,
-                                                   struct scsi_cmnd *scp,
-                                                   int *frame_count)
+static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
 {
-       u32 logical_cmd;
-       struct megasas_cmd *cmd;
-
-       /*
-        * Find out if this is logical or physical drive command.
-        */
-       logical_cmd = MEGASAS_IS_LOGICAL(scp);
-
-       /*
-        * Logical drive command
-        */
-       if (logical_cmd) {
-
-               if (scp->device->id >= MEGASAS_MAX_LD) {
-                       scp->result = DID_BAD_TARGET << 16;
-                       return NULL;
-               }
-
-               switch (scp->cmnd[0]) {
-
-               case READ_10:
-               case WRITE_10:
-               case READ_12:
-               case WRITE_12:
-               case READ_6:
-               case WRITE_6:
-               case READ_16:
-               case WRITE_16:
-                       /*
-                        * Fail for LUN > 0
-                        */
-                       if (scp->device->lun) {
-                               scp->result = DID_BAD_TARGET << 16;
-                               return NULL;
-                       }
-
-                       cmd = megasas_get_cmd(instance);
-
-                       if (!cmd) {
-                               scp->result = DID_IMM_RETRY << 16;
-                               return NULL;
-                       }
-
-                       *frame_count = megasas_build_ldio(instance, scp, cmd);
-
-                       if (!(*frame_count)) {
-                               megasas_return_cmd(instance, cmd);
-                               return NULL;
-                       }
-
-                       return cmd;
-
-               default:
-                       /*
-                        * Fail for LUN > 0
-                        */
-                       if (scp->device->lun) {
-                               scp->result = DID_BAD_TARGET << 16;
-                               return NULL;
-                       }
-
-                       cmd = megasas_get_cmd(instance);
-
-                       if (!cmd) {
-                               scp->result = DID_IMM_RETRY << 16;
-                               return NULL;
-                       }
-
-                       *frame_count = megasas_build_dcdb(instance, scp, cmd);
-
-                       if (!(*frame_count)) {
-                               megasas_return_cmd(instance, cmd);
-                               return NULL;
-                       }
-
-                       return cmd;
-               }
-       } else {
-               cmd = megasas_get_cmd(instance);
-
-               if (!cmd) {
-                       scp->result = DID_IMM_RETRY << 16;
-                       return NULL;
-               }
-
-               *frame_count = megasas_build_dcdb(instance, scp, cmd);
-
-               if (!(*frame_count)) {
-                       megasas_return_cmd(instance, cmd);
-                       return NULL;
-               }
-
-               return cmd;
+       if (!MEGASAS_IS_LOGICAL(cmd))
+               return 0;
+       switch (cmd->cmnd[0]) {
+       case READ_10:
+       case WRITE_10:
+       case READ_12:
+       case WRITE_12:
+       case READ_6:
+       case WRITE_6:
+       case READ_16:
+       case WRITE_16:
+               return 1;
+       default:
+               return 0;
        }
-
-       return NULL;
 }
 
 /**
@@ -684,13 +664,27 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
        scmd->scsi_done = done;
        scmd->result = 0;
 
-       cmd = megasas_build_cmd(instance, scmd, &frame_count);
-
-       if (!cmd) {
-               done(scmd);
-               return 0;
+       if (MEGASAS_IS_LOGICAL(scmd) &&
+           (scmd->device->id >= MEGASAS_MAX_LD || scmd->device->lun)) {
+               scmd->result = DID_BAD_TARGET << 16;
+               goto out_done;
        }
 
+       cmd = megasas_get_cmd(instance);
+       if (!cmd)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
+       /*
+        * Logical drive command
+        */
+       if (megasas_is_ldio(scmd))
+               frame_count = megasas_build_ldio(instance, scmd, cmd);
+       else
+               frame_count = megasas_build_dcdb(instance, scmd, cmd);
+
+       if (!frame_count)
+               goto out_return_cmd;
+
        cmd->scmd = scmd;
        scmd->SCp.ptr = (char *)cmd;
        scmd->SCp.sent_command = jiffies;
@@ -702,10 +696,15 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
        instance->fw_outstanding++;
        spin_unlock_irqrestore(&instance->instance_lock, flags);
 
-       writel(((cmd->frame_phys_addr >> 3) | (cmd->frame_count - 1)),
-              &instance->reg_set->inbound_queue_port);
+       instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
 
        return 0;
+
+ out_return_cmd:
+       megasas_return_cmd(instance, cmd);
+ out_done:
+       done(scmd);
+       return 0;
 }
 
 /**
@@ -1108,7 +1107,6 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 static int
 megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
 {
-       u32 status;
        u32 producer;
        u32 consumer;
        u32 context;
@@ -1116,17 +1114,10 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
 
        /*
         * Check if it is our interrupt
+        * Clear the interrupt 
         */
-       status = readl(&instance->reg_set->outbound_intr_status);
-
-       if (!(status & MFI_OB_INTR_STATUS_MASK)) {
+       if(instance->instancet->clear_intr(instance->reg_set))
                return IRQ_NONE;
-       }
-
-       /*
-        * Clear the interrupt by writing back the same value
-        */
-       writel(status, &instance->reg_set->outbound_intr_status);
 
        producer = *instance->producer;
        consumer = *instance->consumer;
@@ -1160,7 +1151,7 @@ static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
 
 /**
  * megasas_transition_to_ready -       Move the FW to READY state
- * @reg_set:                           MFI register set
+ * @instance:                          Adapter soft state
  *
  * During the initialization, FW passes can potentially be in any one of
  * several possible states. If the FW in operational, waiting-for-handshake
@@ -1168,14 +1159,14 @@ static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
  * has to wait for the ready state.
  */
 static int
-megasas_transition_to_ready(struct megasas_register_set __iomem * reg_set)
+megasas_transition_to_ready(struct megasas_instance* instance)
 {
        int i;
        u8 max_wait;
        u32 fw_state;
        u32 cur_state;
 
-       fw_state = readl(&reg_set->outbound_msg_0) & MFI_STATE_MASK;
+       fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
 
        while (fw_state != MFI_STATE_READY) {
 
@@ -1193,7 +1184,7 @@ megasas_transition_to_ready(struct megasas_register_set __iomem * reg_set)
                         * Set the CLR bit in inbound doorbell
                         */
                        writel(MFI_INIT_CLEAR_HANDSHAKE,
-                              &reg_set->inbound_doorbell);
+                               &instance->reg_set->inbound_doorbell);
 
                        max_wait = 2;
                        cur_state = MFI_STATE_WAIT_HANDSHAKE;
@@ -1203,8 +1194,8 @@ megasas_transition_to_ready(struct megasas_register_set __iomem * reg_set)
                        /*
                         * Bring it to READY state; assuming max wait 2 secs
                         */
-                       megasas_disable_intr(reg_set);
-                       writel(MFI_INIT_READY, &reg_set->inbound_doorbell);
+                       megasas_disable_intr(instance->reg_set);
+                       writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
 
                        max_wait = 10;
                        cur_state = MFI_STATE_OPERATIONAL;
@@ -1253,8 +1244,8 @@ megasas_transition_to_ready(struct megasas_register_set __iomem * reg_set)
                 * The cur_state should not last for more than max_wait secs
                 */
                for (i = 0; i < (max_wait * 1000); i++) {
-                       fw_state = MFI_STATE_MASK &
-                           readl(&reg_set->outbound_msg_0);
+                       fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &  
+                                       MFI_STATE_MASK ;
 
                        if (fw_state == cur_state) {
                                msleep(1);
@@ -1616,18 +1607,20 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 
        reg_set = instance->reg_set;
 
+       instance->instancet = &megasas_instance_template_xscale;
+
        /*
         * We expect the FW state to be READY
         */
-       if (megasas_transition_to_ready(instance->reg_set))
+       if (megasas_transition_to_ready(instance))
                goto fail_ready_state;
 
        /*
         * Get various operational parameters from status register
         */
-       instance->max_fw_cmds = readl(&reg_set->outbound_msg_0) & 0x00FFFF;
-       instance->max_num_sge = (readl(&reg_set->outbound_msg_0) & 0xFF0000) >>
-           0x10;
+       instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+       instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >> 
+                                       0x10;
        /*
         * Create a pool of commands
         */
@@ -1936,8 +1929,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
        /*
         * Issue the aen registration frame
         */
-       writel(cmd->frame_phys_addr >> 3,
-              &instance->reg_set->inbound_queue_port);
+       instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
 
        return 0;
 }
@@ -2126,7 +2118,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                goto fail_irq;
        }
 
-       megasas_enable_intr(instance->reg_set);
+       instance->instancet->enable_intr(instance->reg_set);
 
        /*
         * Store instance in PCI softstate
@@ -2681,9 +2673,8 @@ megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
                          unsigned long arg)
 {
        switch (cmd) {
-       case MEGASAS_IOC_FIRMWARE:{
-                       return megasas_mgmt_compat_ioctl_fw(file, arg);
-               }
+       case MEGASAS_IOC_FIRMWARE32:
+               return megasas_mgmt_compat_ioctl_fw(file, arg);
        case MEGASAS_IOC_GET_AEN:
                return megasas_mgmt_ioctl_aen(file, arg);
        }
index eaec9d531424cc8359e273629d0eebb677725360..d6d166c0663ff664930b06432b4c2753c93631b3 100644 (file)
 /**
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "00.00.02.00-rc4"
-#define MEGASAS_RELDATE                                "Sep 16, 2005"
-#define MEGASAS_EXT_VERSION                    "Fri Sep 16 12:37:08 EDT 2005"
-
+#define MEGASAS_VERSION                                "00.00.02.02"
+#define MEGASAS_RELDATE                                "Jan 23, 2006"
+#define MEGASAS_EXT_VERSION                    "Mon Jan 23 14:09:01 PST 2006"
 /*
  * =====================================
  * MegaRAID SAS MFI firmware definitions
@@ -1013,6 +1012,16 @@ struct megasas_evt_detail {
 
 } __attribute__ ((packed));
 
+ struct megasas_instance_template {
+       void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
+
+       void (*enable_intr)(struct megasas_register_set __iomem *) ;
+
+       int (*clear_intr)(struct megasas_register_set __iomem *);
+
+       u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
+ };
+
 struct megasas_instance {
 
        u32 *producer;
@@ -1056,6 +1065,8 @@ struct megasas_instance {
        u32 fw_outstanding;
        u32 hw_crit_error;
        spinlock_t instance_lock;
+
+       struct megasas_instance_template *instancet;
 };
 
 #define MEGASAS_IS_LOGICAL(scp)                                                \
@@ -1125,11 +1136,10 @@ struct compat_megasas_iocpacket {
        struct compat_iovec sgl[MAX_IOCTL_SGE];
 } __attribute__ ((packed));
 
-#define MEGASAS_IOC_FIRMWARE   _IOWR('M', 1, struct compat_megasas_iocpacket)
-#else
-#define MEGASAS_IOC_FIRMWARE   _IOWR('M', 1, struct megasas_iocpacket)
 #endif
 
+#define MEGASAS_IOC_FIRMWARE   _IOWR('M', 1, struct megasas_iocpacket)
+#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket)
 #define MEGASAS_IOC_GET_AEN    _IOW('M', 3, struct megasas_aen)
 
 struct megasas_mgmt_info {
index 0878f95b54499fc0c26a807624c3cb1345821b0a..e0230249fa0fb55cb9cda06f399b2c8ee0318e9f 100644 (file)
 * General Public License for more details.
 *
 ******************************************************************************/
-#define QLA1280_VERSION      "3.25"
+#define QLA1280_VERSION      "3.26"
 /*****************************************************************************
     Revision History:
+    Rev  3.26, January 16, 2006 Jes Sorensen
+       - Ditch all < 2.6 support
     Rev  3.25.1, February 10, 2005 Christoph Hellwig
        - use pci_map_single to map non-S/G requests
        - remove qla1280_proc_info
 #include <asm/types.h>
 #include <asm/system.h>
 
-#if LINUX_VERSION_CODE >= 0x020545
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
-#else
-#include <linux/blk.h>
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "sd.h"
-#endif
 
 #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
 #include <asm/sn/io.h>
 #endif
 
-#if LINUX_VERSION_CODE < 0x020407
-#error "Kernels older than 2.4.7 are no longer supported"
+#if LINUX_VERSION_CODE < 0x020600
+#error "Kernels older than 2.6.0 are no longer supported"
 #endif
 
 
 
 #define NVRAM_DELAY()                  udelay(500)     /* 2 microseconds */
 
-#if LINUX_VERSION_CODE < 0x020500
-#define HOST_LOCK                      &io_request_lock
-#define irqreturn_t                    void
-#define IRQ_RETVAL(foo)
-#define MSG_ORDERED_TAG                        1
-
-#define DMA_BIDIRECTIONAL      SCSI_DATA_UNKNOWN
-#define DMA_TO_DEVICE          SCSI_DATA_WRITE
-#define DMA_FROM_DEVICE                SCSI_DATA_READ
-#define DMA_NONE               SCSI_DATA_NONE
-
-#ifndef HAVE_SECTOR_T
-typedef unsigned int sector_t;
-#endif
-
-static inline void
-scsi_adjust_queue_depth(struct scsi_device *device, int tag, int depth)
-{
-       if (tag) {
-               device->tagged_queue = tag;
-               device->current_tag = 0;
-       }
-       device->queue_depth = depth;
-}
-static inline struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *t, size_t s)
-{
-       return scsi_register(t, s);
-}
-static inline void scsi_host_put(struct Scsi_Host *h)
-{
-       scsi_unregister(h);
-}
-#else
-#define HOST_LOCK                      ha->host->host_lock
-#endif
-#if LINUX_VERSION_CODE < 0x020600
-#define DEV_SIMPLE_TAGS(device)                device->tagged_queue
-/*
- * Hack around that qla1280_remove_one is called from
- * qla1280_release in 2.4
- */
-#undef __devexit
-#define __devexit
-#else
-#define DEV_SIMPLE_TAGS(device)                device->simple_tags
-#endif
 #if defined(__ia64__) && !defined(ia64_platform_is)
 #define ia64_platform_is(foo)          (!strcmp(x, platform_name))
 #endif
@@ -506,9 +455,6 @@ static void qla1280_remove_one(struct pci_dev *);
  *  QLogic Driver Support Function Prototypes.
  */
 static void qla1280_done(struct scsi_qla_host *);
-#if LINUX_VERSION_CODE < 0x020545
-static void qla1280_get_target_options(struct scsi_cmnd *, struct scsi_qla_host *);
-#endif
 static int qla1280_get_token(char *);
 static int qla1280_setup(char *s) __init;
 
@@ -610,11 +556,7 @@ __setup("qla1280=", qla1280_setup);
 #define        CMD_SNSLEN(Cmnd)        sizeof(Cmnd->sense_buffer)
 #define        CMD_RESULT(Cmnd)        Cmnd->result
 #define        CMD_HANDLE(Cmnd)        Cmnd->host_scribble
-#if LINUX_VERSION_CODE < 0x020545
-#define CMD_REQUEST(Cmnd)      Cmnd->request.cmd
-#else
 #define CMD_REQUEST(Cmnd)      Cmnd->request->cmd
-#endif
 
 #define CMD_HOST(Cmnd)         Cmnd->device->host
 #define SCSI_BUS_32(Cmnd)      Cmnd->device->channel
@@ -1064,10 +1006,10 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
        add_timer(&timer);
 
        /* wait for the action to complete (or the timer to expire) */
-       spin_unlock_irq(HOST_LOCK);
+       spin_unlock_irq(ha->host->host_lock);
        wait_for_completion(&wait);
        del_timer_sync(&timer);
-       spin_lock_irq(HOST_LOCK);
+       spin_lock_irq(ha->host->host_lock);
        sp->wait = NULL;
 
        /* the only action we might get a fail for is abort */
@@ -1173,96 +1115,6 @@ qla1280_biosparam(struct scsi_device *sdev, struct block_device *bdev,
        return 0;
 }
 
-#if LINUX_VERSION_CODE < 0x020600
-static int
-qla1280_detect(struct scsi_host_template *template)
-{
-       struct pci_device_id *id = &qla1280_pci_tbl[0];
-       struct pci_dev *pdev = NULL;
-       int num_hosts = 0;
-
-       if (sizeof(struct srb) > sizeof(Scsi_Pointer)) {
-               printk(KERN_WARNING
-                      "qla1280: struct srb too big, aborting\n");
-               return 0;
-       }
-
-       if ((DMA_BIDIRECTIONAL != PCI_DMA_BIDIRECTIONAL) ||
-           (DMA_TO_DEVICE != PCI_DMA_TODEVICE) ||
-           (DMA_FROM_DEVICE != PCI_DMA_FROMDEVICE) ||
-           (DMA_NONE != PCI_DMA_NONE)) {
-               printk(KERN_WARNING
-                      "qla1280: dma direction bits don't match\n");
-               return 0;
-       }
-
-#ifdef MODULE
-       /*
-        * If we are called as a module, the qla1280 pointer may not be null
-        * and it would point to our bootup string, just like on the lilo
-        * command line.  IF not NULL, then process this config string with
-        * qla1280_setup
-        *
-        * Boot time Options
-        * To add options at boot time add a line to your lilo.conf file like:
-        * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}"
-        * which will result in the first four devices on the first two
-        * controllers being set to a tagged queue depth of 32.
-        */
-       if (qla1280)
-               qla1280_setup(qla1280);
-#endif
-
-       /* First Initialize QLA12160 on PCI Bus 1 Dev 2 */
-       while ((pdev = pci_find_device(id->vendor, id->device, pdev))) {
-               if (pdev->bus->number == 1 && PCI_SLOT(pdev->devfn) == 2) {
-                       if (!qla1280_probe_one(pdev, id))
-                               num_hosts++;
-               }
-       }
-
-       pdev = NULL;
-       /* Try and find each different type of adapter we support */
-       for (id = &qla1280_pci_tbl[0]; id->device; id++) {
-               while ((pdev = pci_find_device(id->vendor, id->device, pdev))) {
-                       /*
-                        * skip QLA12160 already initialized on
-                        * PCI Bus 1 Dev 2 since we already initialized
-                        * and presented it
-                        */
-                       if (id->device == PCI_DEVICE_ID_QLOGIC_ISP12160 &&
-                           pdev->bus->number == 1 &&
-                           PCI_SLOT(pdev->devfn) == 2)
-                               continue;
-
-                       if (!qla1280_probe_one(pdev, id))
-                               num_hosts++;
-               }
-       }
-
-       return num_hosts;
-}
-
-/*
- * This looks a bit ugly as we could just pass down host to
- * qla1280_remove_one, but I want to keep qla1280_release purely a wrapper
- * around pci_driver::remove as used from 2.6 onwards.
- */
-static int
-qla1280_release(struct Scsi_Host *host)
-{
-       struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
-
-       qla1280_remove_one(ha->pdev);
-       return 0;
-}
-
-static int
-qla1280_biosparam_old(Disk * disk, kdev_t dev, int geom[])
-{
-       return qla1280_biosparam(disk->device, NULL, disk->capacity, geom);
-}
-#endif
  
 /* disable risc and host interrupts */
 static inline void
@@ -1295,7 +1147,7 @@ qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
        ENTER_INTR ("qla1280_intr_handler");
        ha = (struct scsi_qla_host *)dev_id;
 
-       spin_lock(HOST_LOCK);
+       spin_lock(ha->host->host_lock);
 
        ha->isr_count++;
        reg = ha->iobase;
@@ -1311,7 +1163,7 @@ qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
        if (!list_empty(&ha->done_q))
                qla1280_done(ha);
 
-       spin_unlock(HOST_LOCK);
+       spin_unlock(ha->host->host_lock);
 
        qla1280_enable_intrs(ha);
 
@@ -1411,11 +1263,9 @@ qla1280_slave_configure(struct scsi_device *device)
                scsi_adjust_queue_depth(device, 0, default_depth);
        }
 
-#if LINUX_VERSION_CODE > 0x020500
        nv->bus[bus].target[target].parameter.enable_sync = device->sdtr;
        nv->bus[bus].target[target].parameter.enable_wide = device->wdtr;
        nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = device->ppr;
-#endif
 
        if (driver_setup.no_sync ||
            (driver_setup.sync_mask &&
@@ -1432,38 +1282,14 @@ qla1280_slave_configure(struct scsi_device *device)
                        nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 0;
        }
 
-       spin_lock_irqsave(HOST_LOCK, flags);
+       spin_lock_irqsave(ha->host->host_lock, flags);
        if (nv->bus[bus].target[target].parameter.enable_sync)
                status = qla1280_set_target_parameters(ha, bus, target);
        qla1280_get_target_parameters(ha, device);
-       spin_unlock_irqrestore(HOST_LOCK, flags);
+       spin_unlock_irqrestore(ha->host->host_lock, flags);
        return status;
 }
 
-#if LINUX_VERSION_CODE < 0x020545
-/**************************************************************************
- *   qla1280_select_queue_depth
- *
- *   Sets the queue depth for each SCSI device hanging off the input
- *   host adapter.  We use a queue depth of 2 for devices that do not
- *   support tagged queueing.
- **************************************************************************/
-static void
-qla1280_select_queue_depth(struct Scsi_Host *host, struct scsi_device *sdev_q)
-{
-       struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
-       struct scsi_device *sdev;
-
-       ENTER("qla1280_select_queue_depth");
-       for (sdev = sdev_q; sdev; sdev = sdev->next)
-               if (sdev->host == host)
-                       qla1280_slave_configure(sdev);
-
-       if (sdev_q)
-               qla1280_check_for_dead_scsi_bus(ha, sdev_q->channel);
-       LEAVE("qla1280_select_queue_depth");
-}
-#endif
 
 /*
  * qla1280_done
@@ -1523,10 +1349,6 @@ qla1280_done(struct scsi_qla_host *ha)
                CMD_HANDLE(sp->cmd) = (unsigned char *)INVALID_HANDLE;
                ha->actthreads--;
 
-#if LINUX_VERSION_CODE < 0x020500
-               if (cmd->cmnd[0] == INQUIRY)
-                       qla1280_get_target_options(cmd, ha);
-#endif
                (*(cmd)->scsi_done)(cmd);
 
                if(sp->wait != NULL)
@@ -1655,9 +1477,7 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha)
        struct device_reg __iomem *reg;
        int status;
        int bus;
-#if LINUX_VERSION_CODE > 0x020500
        unsigned long flags;
-#endif
 
        ENTER("qla1280_initialize_adapter");
 
@@ -1695,15 +1515,12 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha)
                        "NVRAM\n");
        }
 
-#if LINUX_VERSION_CODE >= 0x020500
        /*
         * It's necessary to grab the spin here as qla1280_mailbox_command
         * needs to be able to drop the lock unconditionally to wait
         * for completion.
-        * In 2.4 ->detect is called with the io_request_lock held.
         */
-       spin_lock_irqsave(HOST_LOCK, flags);
-#endif
+       spin_lock_irqsave(ha->host->host_lock, flags);
 
        status = qla1280_load_firmware(ha);
        if (status) {
@@ -1735,9 +1552,8 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha)
 
        ha->flags.online = 1;
  out:
-#if LINUX_VERSION_CODE >= 0x020500
-       spin_unlock_irqrestore(HOST_LOCK, flags);
-#endif
+       spin_unlock_irqrestore(ha->host->host_lock, flags);
+
        if (status)
                dprintk(2, "qla1280_initialize_adapter: **** FAILED ****\n");
 
@@ -2650,14 +2466,14 @@ qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb)
        timer.function = qla1280_mailbox_timeout;
        add_timer(&timer);
 
-       spin_unlock_irq(HOST_LOCK);
+       spin_unlock_irq(ha->host->host_lock);
        WRT_REG_WORD(&reg->host_cmd, HC_SET_HOST_INT);
        data = qla1280_debounce_register(&reg->istatus);
 
        wait_for_completion(&wait);
        del_timer_sync(&timer);
 
-       spin_lock_irq(HOST_LOCK);
+       spin_lock_irq(ha->host->host_lock);
 
        ha->mailbox_wait = NULL;
 
@@ -2770,9 +2586,9 @@ qla1280_bus_reset(struct scsi_qla_host *ha, int bus)
                        ha->bus_settings[bus].scsi_bus_dead = 1;
                ha->bus_settings[bus].failed_reset_count++;
        } else {
-               spin_unlock_irq(HOST_LOCK);
+               spin_unlock_irq(ha->host->host_lock);
                ssleep(reset_delay);
-               spin_lock_irq(HOST_LOCK);
+               spin_lock_irq(ha->host->host_lock);
 
                ha->bus_settings[bus].scsi_bus_dead = 0;
                ha->bus_settings[bus].failed_reset_count = 0;
@@ -3078,7 +2894,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
                (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd);
 
        /* Enable simple tag queuing if device supports it. */
-       if (DEV_SIMPLE_TAGS(cmd->device))
+       if (cmd->device->simple_tags)
                pkt->control_flags |= cpu_to_le16(BIT_3);
 
        /* Load SCSI command packet. */
@@ -3377,7 +3193,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
                (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd);
 
        /* Enable simple tag queuing if device supports it. */
-       if (DEV_SIMPLE_TAGS(cmd->device))
+       if (cmd->device->simple_tags)
                pkt->control_flags |= cpu_to_le16(BIT_3);
 
        /* Load SCSI command packet. */
@@ -3889,50 +3705,6 @@ qla1280_rst_aen(struct scsi_qla_host *ha)
 }
 
 
-#if LINUX_VERSION_CODE < 0x020500
-/*
- *
- */
-static void
-qla1280_get_target_options(struct scsi_cmnd *cmd, struct scsi_qla_host *ha)
-{
-       unsigned char *result;
-       struct nvram *n;
-       int bus, target, lun;
-
-       bus = SCSI_BUS_32(cmd);
-       target = SCSI_TCN_32(cmd);
-       lun = SCSI_LUN_32(cmd);
-
-       /*
-        * Make sure to not touch anything if someone is using the
-        * sg interface.
-        */
-       if (cmd->use_sg || (CMD_RESULT(cmd) >> 16) != DID_OK || lun)
-               return;
-
-       result = cmd->request_buffer;
-       n = &ha->nvram;
-
-       n->bus[bus].target[target].parameter.enable_wide = 0;
-       n->bus[bus].target[target].parameter.enable_sync = 0;
-       n->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 0;
-
-        if (result[7] & 0x60)
-               n->bus[bus].target[target].parameter.enable_wide = 1;
-        if (result[7] & 0x10)
-               n->bus[bus].target[target].parameter.enable_sync = 1;
-       if ((result[2] >= 3) && (result[4] + 5 > 56) &&
-           (result[56] & 0x4))
-               n->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 1;
-
-       dprintk(2, "get_target_options(): wide %i, sync %i, ppr %i\n",
-               n->bus[bus].target[target].parameter.enable_wide,
-               n->bus[bus].target[target].parameter.enable_sync,
-               n->bus[bus].target[target].ppr_1x160.flags.enable_ppr);
-}
-#endif
-
 /*
  *  qla1280_status_entry
  *      Processes received ISP status entry.
@@ -4271,7 +4043,7 @@ qla1280_get_target_parameters(struct scsi_qla_host *ha,
        } else
                printk(" Async");
 
-       if (DEV_SIMPLE_TAGS(device))
+       if (device->simple_tags)
                printk(", Tagged queuing: depth %d", device->queue_depth);
        printk("\n");
 }
@@ -4485,7 +4257,7 @@ qla1280_get_token(char *str)
        return ret;
 }
 
-#if LINUX_VERSION_CODE >= 0x020600
+
 static struct scsi_host_template qla1280_driver_template = {
        .module                 = THIS_MODULE,
        .proc_name              = "qla1280",
@@ -4504,27 +4276,7 @@ static struct scsi_host_template qla1280_driver_template = {
        .cmd_per_lun            = 1,
        .use_clustering         = ENABLE_CLUSTERING,
 };
-#else
-static struct scsi_host_template qla1280_driver_template = {
-       .proc_name              = "qla1280",
-       .name                   = "Qlogic ISP 1280/12160",
-       .detect                 = qla1280_detect,
-       .release                = qla1280_release,
-       .info                   = qla1280_info,
-       .queuecommand           = qla1280_queuecommand,
-       .eh_abort_handler       = qla1280_eh_abort,
-       .eh_device_reset_handler= qla1280_eh_device_reset,
-       .eh_bus_reset_handler   = qla1280_eh_bus_reset,
-       .eh_host_reset_handler  = qla1280_eh_adapter_reset,
-       .bios_param             = qla1280_biosparam_old,
-       .can_queue              = 0xfffff,
-       .this_id                = -1,
-       .sg_tablesize           = SG_ALL,
-       .cmd_per_lun            = 1,
-       .use_clustering         = ENABLE_CLUSTERING,
-       .use_new_eh_code        = 1,
-};
-#endif
+
 
 static int __devinit
 qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -4615,10 +4367,6 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        host->max_sectors = 1024;
        host->unique_id = host->host_no;
 
-#if LINUX_VERSION_CODE < 0x020545
-       host->select_queue_depths = qla1280_select_queue_depth;
-#endif
-
        error = -ENODEV;
 
 #if MEMORY_MAPPED_IO
@@ -4666,21 +4414,15 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        pci_set_drvdata(pdev, host);
 
-#if LINUX_VERSION_CODE >= 0x020600
        error = scsi_add_host(host, &pdev->dev);
        if (error)
                goto error_disable_adapter;
        scsi_scan_host(host);
-#else
-       scsi_set_pci_device(host, pdev);
-#endif
 
        return 0;
 
-#if LINUX_VERSION_CODE >= 0x020600
  error_disable_adapter:
        qla1280_disable_intrs(ha);
-#endif
  error_free_irq:
        free_irq(pdev->irq, ha);
  error_release_region:
@@ -4712,9 +4454,7 @@ qla1280_remove_one(struct pci_dev *pdev)
        struct Scsi_Host *host = pci_get_drvdata(pdev);
        struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
 
-#if LINUX_VERSION_CODE >= 0x020600
        scsi_remove_host(host);
-#endif
 
        qla1280_disable_intrs(ha);
 
@@ -4738,7 +4478,6 @@ qla1280_remove_one(struct pci_dev *pdev)
        scsi_host_put(host);
 }
 
-#if LINUX_VERSION_CODE >= 0x020600
 static struct pci_driver qla1280_pci_driver = {
        .name           = "qla1280",
        .id_table       = qla1280_pci_tbl,
@@ -4784,10 +4523,6 @@ qla1280_exit(void)
 module_init(qla1280_init);
 module_exit(qla1280_exit);
 
-#else
-# define driver_template qla1280_driver_template
-# include "scsi_module.c"
-#endif
 
 MODULE_AUTHOR("Qlogic & Jes Sorensen");
 MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver");
index 79d8a914f9d0f4ddb213fd1bd9d5b63f68c39138..bad066e5772acfce0079784ef2fada7c73a9a707 100644 (file)
@@ -1680,7 +1680,8 @@ typedef struct fc_port {
        uint8_t mp_byte;                /* multi-path byte (not used) */
        uint8_t cur_path;               /* current path id */
 
-       struct fc_rport *rport;
+       spinlock_t rport_lock;
+       struct fc_rport *rport, *drport;
        u32 supported_classes;
        struct work_struct rport_add_work;
        struct work_struct rport_del_work;
@@ -2270,6 +2271,7 @@ typedef struct scsi_qla_host {
 #define LOOP_RESET_NEEDED      24
 #define BEACON_BLINK_NEEDED    25
 #define REGISTER_FDMI_NEEDED   26
+#define FCPORT_UPDATE_NEEDED   27
 
        uint32_t        device_flags;
 #define DFLG_LOCAL_DEVICES             BIT_0
index 32be4c14cccb50044a77b1c53b5b9be1eb5cc81d..35266bd5d5383ba75919f1e285601577ad3abd54 100644 (file)
@@ -47,9 +47,11 @@ extern int qla2x00_local_device_login(scsi_qla_host_t *, uint16_t);
 extern void qla2x00_restart_queues(scsi_qla_host_t *, uint8_t);
 
 extern void qla2x00_rescan_fcports(scsi_qla_host_t *);
+extern void qla2x00_update_fcports(scsi_qla_host_t *);
 
 extern int qla2x00_abort_isp(scsi_qla_host_t *);
 
+extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
 extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *);
 
 /*
@@ -70,8 +72,8 @@ extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
 
 extern void qla2x00_cmd_timeout(srb_t *);
 
-extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int);
-extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *);
+extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int);
+extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int);
 
 extern void qla2x00_blink_led(scsi_qla_host_t *);
 
index a91fea69ad63597b938b9afde16260ebb358d476..e67bb099781818339b6a1ef6342694c54825860c 100644 (file)
@@ -32,7 +32,6 @@ static int qla2x00_fw_ready(scsi_qla_host_t *);
 static int qla2x00_configure_hba(scsi_qla_host_t *);
 static int qla2x00_configure_loop(scsi_qla_host_t *);
 static int qla2x00_configure_local_loop(scsi_qla_host_t *);
-static void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
 static int qla2x00_configure_fabric(scsi_qla_host_t *);
 static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *);
 static int qla2x00_device_resync(scsi_qla_host_t *);
@@ -1688,10 +1687,16 @@ static void
 qla2x00_rport_del(void *data)
 {
        fc_port_t *fcport = data;
+       struct fc_rport *rport;
+       unsigned long flags;
+
+       spin_lock_irqsave(&fcport->rport_lock, flags);
+       rport = fcport->drport;
+       fcport->drport = NULL;
+       spin_unlock_irqrestore(&fcport->rport_lock, flags);
+       if (rport)
+               fc_remote_port_delete(rport);
 
-       if (fcport->rport)
-               fc_remote_port_delete(fcport->rport);
-       fcport->rport = NULL;
 }
 
 /**
@@ -1719,6 +1724,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
        atomic_set(&fcport->state, FCS_UNCONFIGURED);
        fcport->flags = FCF_RLC_SUPPORT;
        fcport->supported_classes = FC_COS_UNSPECIFIED;
+       spin_lock_init(&fcport->rport_lock);
        INIT_WORK(&fcport->rport_add_work, qla2x00_rport_add, fcport);
        INIT_WORK(&fcport->rport_del_work, qla2x00_rport_del, fcport);
 
@@ -2008,7 +2014,7 @@ qla2x00_probe_for_all_luns(scsi_qla_host_t *ha)
 {
        fc_port_t       *fcport;
 
-       qla2x00_mark_all_devices_lost(ha);
+       qla2x00_mark_all_devices_lost(ha, 0);
        list_for_each_entry(fcport, &ha->fcports, list) {
                if (fcport->port_type != FCT_TARGET)
                        continue;
@@ -2032,13 +2038,9 @@ qla2x00_probe_for_all_luns(scsi_qla_host_t *ha)
  * Context:
  *     Kernel context.
  */
-static void
+void
 qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
-       uint16_t        index;
-       unsigned long flags;
-       srb_t *sp;
-
        fcport->ha = ha;
        fcport->login_retry = 0;
        fcport->port_login_retry_count = ha->port_down_retry_count *
@@ -2047,28 +2049,6 @@ qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
            PORT_RETRY_TIME);
        fcport->flags &= ~FCF_LOGIN_NEEDED;
 
-       /*
-        * Check for outstanding cmd on tape Bypass LUN discovery if active
-        * command on tape.
-        */
-       if (fcport->flags & FCF_TAPE_PRESENT) {
-               spin_lock_irqsave(&ha->hardware_lock, flags);
-               for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
-                       fc_port_t *sfcp;
-
-                       if ((sp = ha->outstanding_cmds[index]) != 0) {
-                               sfcp = sp->fcport;
-                               if (sfcp == fcport) {
-                                       atomic_set(&fcport->state, FCS_ONLINE);
-                                       spin_unlock_irqrestore(
-                                           &ha->hardware_lock, flags);
-                                       return;
-                               }
-                       }
-               }
-               spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       }
-
        if (fcport->port_type == FCT_INITIATOR ||
            fcport->port_type == FCT_BROADCAST)
                fcport->device_type = TYPE_PROCESSOR;
@@ -2084,24 +2064,29 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
        struct fc_rport_identifiers rport_ids;
        struct fc_rport *rport;
+       unsigned long flags;
 
-       if (fcport->rport) {
-               fc_remote_port_delete(fcport->rport);
-               fcport->rport = NULL;
-       }
+       if (fcport->drport)
+               qla2x00_rport_del(fcport);
+       if (fcport->rport)
+               return;
 
        rport_ids.node_name = wwn_to_u64(fcport->node_name);
        rport_ids.port_name = wwn_to_u64(fcport->port_name);
        rport_ids.port_id = fcport->d_id.b.domain << 16 |
            fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
        rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
-       fcport->rport = rport = fc_remote_port_add(ha->host, 0, &rport_ids);
+       rport = fc_remote_port_add(ha->host, 0, &rport_ids);
        if (!rport) {
                qla_printk(KERN_WARNING, ha,
                    "Unable to allocate fc remote port!\n");
                return;
        }
+       spin_lock_irqsave(&fcport->rport_lock, flags);
+       fcport->rport = rport;
        *((fc_port_t **)rport->dd_data) = fcport;
+       spin_unlock_irqrestore(&fcport->rport_lock, flags);
+
        rport->supported_classes = fcport->supported_classes;
 
        rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
@@ -2217,12 +2202,11 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
 
                        if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
                                qla2x00_mark_device_lost(ha, fcport,
-                                   ql2xplogiabsentdevice);
+                                   ql2xplogiabsentdevice, 0);
                                if (fcport->loop_id != FC_NO_LOOP_ID &&
                                    (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
                                    fcport->port_type != FCT_INITIATOR &&
                                    fcport->port_type != FCT_BROADCAST) {
-
                                        ha->isp_ops.fabric_logout(ha,
                                            fcport->loop_id,
                                            fcport->d_id.b.domain,
@@ -2694,7 +2678,8 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
                        if (atomic_read(&fcport->state) == FCS_ONLINE) {
                                if (format != 3 ||
                                    fcport->port_type != FCT_INITIATOR) {
-                                       qla2x00_mark_device_lost(ha, fcport, 0);
+                                       qla2x00_mark_device_lost(ha, fcport,
+                                           0, 0);
                                }
                        }
                        fcport->flags &= ~FCF_FARP_DONE;
@@ -2741,8 +2726,7 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *ha, fc_port_t *fcport,
                        ha->isp_ops.fabric_logout(ha, fcport->loop_id,
                            fcport->d_id.b.domain, fcport->d_id.b.area,
                            fcport->d_id.b.al_pa);
-                       qla2x00_mark_device_lost(ha, fcport, 1);
-
+                       qla2x00_mark_device_lost(ha, fcport, 1, 0);
                } else {
                        qla2x00_update_fcport(ha, fcport);
                }
@@ -2855,7 +2839,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
                        ha->isp_ops.fabric_logout(ha, fcport->loop_id,
                            fcport->d_id.b.domain, fcport->d_id.b.area,
                            fcport->d_id.b.al_pa);
-                       qla2x00_mark_device_lost(ha, fcport, 1);
+                       qla2x00_mark_device_lost(ha, fcport, 1, 0);
 
                        rval = 1;
                        break;
@@ -2990,6 +2974,17 @@ qla2x00_rescan_fcports(scsi_qla_host_t *ha)
        qla2x00_probe_for_all_luns(ha);
 }
 
+void
+qla2x00_update_fcports(scsi_qla_host_t *ha)
+{
+       fc_port_t *fcport;
+
+       /* Go with deferred removal of rport references. */
+       list_for_each_entry(fcport, &ha->fcports, list)
+               if (fcport->drport)
+                       qla2x00_rport_del(fcport);
+}
+
 /*
 *  qla2x00_abort_isp
 *      Resets ISP and aborts all outstanding commands.
@@ -3019,7 +3014,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
                atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
                if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
                        atomic_set(&ha->loop_state, LOOP_DOWN);
-                       qla2x00_mark_all_devices_lost(ha);
+                       qla2x00_mark_all_devices_lost(ha, 0);
                } else {
                        if (!atomic_read(&ha->loop_down_timer))
                                atomic_set(&ha->loop_down_timer,
index f63af081d4ff8aaf219e2255e06e7a0c334f7c09..71a46fcee8cc47d3b7e0cba5cf0aad80786f8d2b 100644 (file)
@@ -389,7 +389,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
                        atomic_set(&ha->loop_state, LOOP_DOWN);
                        atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
-                       qla2x00_mark_all_devices_lost(ha);
+                       qla2x00_mark_all_devices_lost(ha, 1);
                }
 
                set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
@@ -432,7 +432,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                        atomic_set(&ha->loop_state, LOOP_DOWN);
                        atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
                        ha->device_flags |= DFLG_NO_CABLE;
-                       qla2x00_mark_all_devices_lost(ha);
+                       qla2x00_mark_all_devices_lost(ha, 1);
                }
 
                ha->flags.management_server_logged_in = 0;
@@ -453,7 +453,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
                        atomic_set(&ha->loop_state, LOOP_DOWN);
                        atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
-                       qla2x00_mark_all_devices_lost(ha);
+                       qla2x00_mark_all_devices_lost(ha, 1);
                }
 
                set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
@@ -482,7 +482,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                        if (!atomic_read(&ha->loop_down_timer))
                                atomic_set(&ha->loop_down_timer,
                                    LOOP_DOWN_TIME);
-                       qla2x00_mark_all_devices_lost(ha);
+                       qla2x00_mark_all_devices_lost(ha, 1);
                }
 
                if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) {
@@ -506,7 +506,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                        if (!atomic_read(&ha->loop_down_timer))
                                atomic_set(&ha->loop_down_timer,
                                    LOOP_DOWN_TIME);
-                       qla2x00_mark_all_devices_lost(ha);
+                       qla2x00_mark_all_devices_lost(ha, 1);
                }
 
                set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
@@ -580,7 +580,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                 */
                atomic_set(&ha->loop_state, LOOP_UP);
 
-               qla2x00_mark_all_devices_lost(ha);
+               qla2x00_mark_all_devices_lost(ha, 1);
 
                ha->flags.rscn_queue_overflow = 1;
 
@@ -1091,7 +1091,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
 
                cp->result = DID_BUS_BUSY << 16;
                if (atomic_read(&fcport->state) == FCS_ONLINE) {
-                       qla2x00_mark_device_lost(ha, fcport, 1);
+                       qla2x00_mark_device_lost(ha, fcport, 1, 1);
                }
                break;
 
@@ -1135,7 +1135,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
 
                /* Check to see if logout occurred. */
                if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT))
-                       qla2x00_mark_device_lost(ha, fcport, 1);
+                       qla2x00_mark_device_lost(ha, fcport, 1, 1);
                break;
 
        case CS_QUEUE_FULL:
index 4916847d84ec9321a58629c0eef15543e73d2873..5866a7c706a82d627e71f597fe89970eb493d10f 100644 (file)
@@ -756,7 +756,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
                if (ret == SUCCESS) {
                        if (fcport->flags & FC_FABRIC_DEVICE) {
                                ha->isp_ops.fabric_logout(ha, fcport->loop_id);
-                               qla2x00_mark_device_lost(ha, fcport);
+                               qla2x00_mark_device_lost(ha, fcport, 0, 0);
                        }
                }
 #endif
@@ -1642,6 +1642,31 @@ qla2x00_free_device(scsi_qla_host_t *ha)
        pci_disable_device(ha->pdev);
 }
 
+static inline void
+qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
+    int defer)
+{
+       unsigned long flags;
+       struct fc_rport *rport;
+
+       if (!fcport->rport)
+               return;
+
+       rport = fcport->rport;
+       if (defer) {
+               spin_lock_irqsave(&fcport->rport_lock, flags);
+               fcport->drport = rport;
+               fcport->rport = NULL;
+               spin_unlock_irqrestore(&fcport->rport_lock, flags);
+               set_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags);
+       } else {
+               spin_lock_irqsave(&fcport->rport_lock, flags);
+               fcport->rport = NULL;
+               spin_unlock_irqrestore(&fcport->rport_lock, flags);
+               fc_remote_port_delete(rport);
+       }
+}
+
 /*
  * qla2x00_mark_device_lost Updates fcport state when device goes offline.
  *
@@ -1652,10 +1677,10 @@ qla2x00_free_device(scsi_qla_host_t *ha)
  * Context:
  */
 void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
-    int do_login)
+    int do_login, int defer)
 {
-       if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport)
-               schedule_work(&fcport->rport_del_work);
+       if (atomic_read(&fcport->state) == FCS_ONLINE)
+               qla2x00_schedule_rport_del(ha, fcport, defer);
 
        /*
         * We may need to retry the login, so don't change the state of the
@@ -1702,7 +1727,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
  * Context:
  */
 void
-qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha)
+qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 {
        fc_port_t *fcport;
 
@@ -1716,10 +1741,13 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha)
                 */
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
                        continue;
-               if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport)
-                       schedule_work(&fcport->rport_del_work);
+               if (atomic_read(&fcport->state) == FCS_ONLINE)
+                       qla2x00_schedule_rport_del(ha, fcport, defer);
                atomic_set(&fcport->state, FCS_DEVICE_LOST);
        }
+
+       if (defer && ha->dpc_wait && !ha->dpc_active)
+               up(ha->dpc_wait);
 }
 
 /*
@@ -2161,6 +2189,9 @@ qla2x00_do_dpc(void *data)
                            ha->host_no));
                }
 
+               if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags))
+                       qla2x00_update_fcports(ha);
+
                if (test_and_clear_bit(LOOP_RESET_NEEDED, &ha->dpc_flags)) {
                        DEBUG(printk("scsi(%ld): dpc: sched loop_reset()\n",
                            ha->host_no));
@@ -2219,13 +2250,8 @@ qla2x00_do_dpc(void *data)
                                                DEBUG(printk("scsi(%ld): port login OK: logged in ID 0x%x\n",
                                                    ha->host_no, fcport->loop_id));
 
-                                               fcport->port_login_retry_count =
-                                                   ha->port_down_retry_count * PORT_RETRY_TIME;
-                                               atomic_set(&fcport->state, FCS_ONLINE);
-                                               atomic_set(&fcport->port_down_timer,
-                                                   ha->port_down_retry_count * PORT_RETRY_TIME);
-
-                                               fcport->login_retry = 0;
+                                               qla2x00_update_fcport(ha,
+                                                   fcport);
                                        } else if (status == 1) {
                                                set_bit(RELOGIN_NEEDED, &ha->dpc_flags);
                                                /* retry the login again */
@@ -2469,6 +2495,7 @@ qla2x00_timer(scsi_qla_host_t *ha)
        if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
            test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) ||
            test_bit(LOOP_RESET_NEEDED, &ha->dpc_flags) ||
+           test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags) ||
            start_dpc ||
            test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
            test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
index a2333d2c7af0be4712651b2780b7cc10566dab3b..5cc97b721661471b38a57346a6bebb759fc9ec10 100644 (file)
@@ -1350,7 +1350,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
        cmnd[4] = SCSI_REMOVAL_PREVENT;
        cmnd[5] = 0;
 
-       scsi_execute_async(sdev, cmnd, DMA_NONE, NULL, 0, 0, 10 * HZ,
+       scsi_execute_async(sdev, cmnd, 6, DMA_NONE, NULL, 0, 0, 10 * HZ,
                           5, NULL, NULL, GFP_KERNEL);
 }
 
index 3574ba935af8ea451741de17ae26b4e77087fe68..4a602853a98e72f89b94757c4b9e56b87587ad53 100644 (file)
@@ -436,6 +436,7 @@ free_bios:
  * scsi_execute_async - insert request
  * @sdev:      scsi device
  * @cmd:       scsi command
+ * @cmd_len:   length of scsi cdb
  * @data_direction: data direction
  * @buffer:    data buffer (this can be a kernel buffer or scatterlist)
  * @bufflen:   len of buffer
@@ -445,7 +446,7 @@ free_bios:
  * @flags:     or into request flags
  **/
 int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
-                      int data_direction, void *buffer, unsigned bufflen,
+                      int cmd_len, int data_direction, void *buffer, unsigned bufflen,
                       int use_sg, int timeout, int retries, void *privdata,
                       void (*done)(void *, char *, int, int), gfp_t gfp)
 {
@@ -472,7 +473,7 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
        if (err)
                goto free_req;
 
-       req->cmd_len = COMMAND_SIZE(cmd[0]);
+       req->cmd_len = cmd_len;
        memcpy(req->cmd, cmd, req->cmd_len);
        req->sense = sioc->sense;
        req->sense_len = 0;
index a3e0b7bc2d7bd1a71b31b0f4be0e091ae5b20b9b..210dab5879fa354bb99031f3e0981ca40e14c446 100644 (file)
@@ -377,7 +377,7 @@ static void sas_phy_release(struct device *dev)
 /**
  * sas_phy_alloc  --  allocates and initialize a SAS PHY structure
  * @parent:    Parent device
- * @number:    Port number
+ * @number:    Phy index
  *
  * Allocates an SAS PHY structure.  It will be added in the device tree
  * below the device specified by @parent, which has to be either a Scsi_Host
@@ -595,8 +595,8 @@ struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent)
        device_initialize(&rphy->dev);
        rphy->dev.parent = get_device(&parent->dev);
        rphy->dev.release = sas_rphy_release;
-       sprintf(rphy->dev.bus_id, "rphy-%d:%d",
-               shost->host_no, parent->number);
+       sprintf(rphy->dev.bus_id, "rphy-%d:%d-%d",
+               shost->host_no, parent->port_identifier, parent->number);
        transport_setup_device(&rphy->dev);
 
        return rphy;
index 78aad9582bcfbef87399ac33e02fa60b39712cdc..7d0700091f3d6417e8c37ab6919b6a0de32042a9 100644 (file)
@@ -741,7 +741,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
        hp->duration = jiffies_to_msecs(jiffies);
 /* Now send everything of to mid-level. The next time we hear about this
    packet is when sg_cmd_done() is called (i.e. a callback). */
-       if (scsi_execute_async(sdp->device, cmnd, data_dir, srp->data.buffer,
+       if (scsi_execute_async(sdp->device, cmnd, hp->cmd_len, data_dir, srp->data.buffer,
                                hp->dxfer_len, srp->data.k_use_sg, timeout,
                                SG_DEFAULT_RETRIES, srp, sg_cmd_done,
                                GFP_ATOMIC)) {
index 13b1d3aac26521cf5b5e1518aaf9d062b5720dbb..7f96f33c1bb1c815b09f88c5458b556ce6c2fc81 100644 (file)
@@ -508,7 +508,7 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd
        STp->buffer->cmdstat.have_sense = 0;
        STp->buffer->syscall_result = 0;
 
-       if (scsi_execute_async(STp->device, cmd, direction,
+       if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction,
                        &((STp->buffer)->sg[0]), bytes, (STp->buffer)->sg_segs,
                               timeout, retries, SRpnt, st_sleep_done, GFP_KERNEL)) {
                /* could not allocate the buffer or request was too large */
index 221999bcf8fe3809b943e4f11c53ba4529810f52..7aef7518b0d1cb4291d38ad3f4e860d67dbbd9a0 100644 (file)
@@ -366,7 +366,7 @@ static struct uart_port serial21285_port = {
        .irq            = NO_IRQ,
        .fifosize       = 16,
        .ops            = &serial21285_ops,
-       .flags          = ASYNC_BOOT_AUTOCONF,
+       .flags          = UPF_BOOT_AUTOCONF,
 };
 
 static void serial21285_setup_ports(void)
index bc36edff205805517a489e945826edce91943640..179c1f065e60a5662498c006f28c48b83828baa1 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/init.h>
 #include <linux/console.h>
 #include <linux/sysrq.h>
-#include <linux/mca.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/tty.h>
@@ -2026,12 +2025,6 @@ static void serial8250_config_port(struct uart_port *port, int flags)
        int probeflags = PROBE_ANY;
        int ret;
 
-       /*
-        * Don't probe for MCA ports on non-MCA machines.
-        */
-       if (up->port.flags & UPF_BOOT_ONLYMCA && !MCA_bus)
-               return;
-
        /*
         * Find the region that we can probe for.  This in turn
         * tells us whether we can probe for the type of port.
@@ -2164,7 +2157,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 /*
  *     Wait for transmitter & holding register to empty
  */
-static inline void wait_for_xmitr(struct uart_8250_port *up)
+static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
 {
        unsigned int status, tmout = 10000;
 
@@ -2178,7 +2171,7 @@ static inline void wait_for_xmitr(struct uart_8250_port *up)
                if (--tmout == 0)
                        break;
                udelay(1);
-       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+       } while ((status & bits) != bits);
 
        /* Wait up to 1s for flow control if necessary */
        if (up->port.flags & UPF_CONS_FLOW) {
@@ -2218,7 +2211,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
         *      Now, do each character
         */
        for (i = 0; i < count; i++, s++) {
-               wait_for_xmitr(up);
+               wait_for_xmitr(up, UART_LSR_THRE);
 
                /*
                 *      Send the character out.
@@ -2226,7 +2219,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
                 */
                serial_out(up, UART_TX, *s);
                if (*s == 10) {
-                       wait_for_xmitr(up);
+                       wait_for_xmitr(up, UART_LSR_THRE);
                        serial_out(up, UART_TX, 13);
                }
        }
@@ -2235,8 +2228,8 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
         *      Finally, wait for transmitter to become empty
         *      and restore the IER
         */
-       wait_for_xmitr(up);
-       serial_out(up, UART_IER, ier);
+       wait_for_xmitr(up, BOTH_EMPTY);
+       serial_out(up, UART_IER, ier | UART_IER_THRI);
 }
 
 static int serial8250_console_setup(struct console *co, char *options)
index 9fd1925de3611feba30e95ef035d01e6658863e4..0d38f0f2ae2975d41f08fa059ab796385be2e71e 100644 (file)
@@ -23,7 +23,7 @@ config SERIAL_8250
          work.)
 
          To compile this driver as a module, choose M here: the
-         module will be called serial.
+         module will be called 8250.
          [WARNING: Do not compile this driver as a module if you are using
          non-standard serial ports, since the configuration information will
          be lost when the driver is unloaded.  This limitation may be lifted
index 3490022e9fdc7e923d265eb06e635f4dc32e5026..429de2723a1c4d95597038625db48e52a966cae3 100644 (file)
@@ -566,7 +566,7 @@ static struct uart_amba_port amba_ports[UART_NR] = {
                        .uartclk        = 14745600,
                        .fifosize       = 16,
                        .ops            = &amba_pl010_pops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .dtr_mask       = 1 << 5,
@@ -581,7 +581,7 @@ static struct uart_amba_port amba_ports[UART_NR] = {
                        .uartclk        = 14745600,
                        .fifosize       = 16,
                        .ops            = &amba_pl010_pops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 1,
                },
                .dtr_mask       = 1 << 7,
index 8ef999481f9386fe351e77e0a7cd9b98d6250d73..ce7b2e4ecd17c33a6fa12e2451f0e6d5ba276c1a 100644 (file)
@@ -410,7 +410,7 @@ static struct uart_port clps711x_ports[UART_NR] = {
                .fifosize       = 16,
                .ops            = &clps711x_pops,
                .line           = 0,
-               .flags          = ASYNC_BOOT_AUTOCONF,
+               .flags          = UPF_BOOT_AUTOCONF,
        },
        {
                .iobase         = SYSCON2,
@@ -419,7 +419,7 @@ static struct uart_port clps711x_ports[UART_NR] = {
                .fifosize       = 16,
                .ops            = &clps711x_pops,
                .line           = 1,
-               .flags          = ASYNC_BOOT_AUTOCONF,
+               .flags          = UPF_BOOT_AUTOCONF,
        }
 };
 
index 587cc6a9511461732d355f7c32b4dc33117d52b3..858048efe1edbd4da7a5d2d49b5fb587a333ba28 100644 (file)
@@ -402,10 +402,10 @@ static int imx_startup(struct uart_port *port)
                             DRIVER_NAME, sport);
        if (retval) goto error_out2;
 
-       retval = request_irq(sport->rtsirq, imx_rtsint, 0,
+       retval = request_irq(sport->rtsirq, imx_rtsint,
+                            SA_TRIGGER_FALLING | SA_TRIGGER_RISING,
                             DRIVER_NAME, sport);
        if (retval) goto error_out3;
-       set_irq_type(sport->rtsirq, IRQT_BOTHEDGE);
 
        /*
         * Finally, clear and enable interrupts
@@ -674,7 +674,7 @@ static struct imx_port imx_ports[] = {
                .irq            = UART1_MINT_RX,
                .uartclk        = 16000000,
                .fifosize       = 8,
-               .flags          = ASYNC_BOOT_AUTOCONF,
+               .flags          = UPF_BOOT_AUTOCONF,
                .ops            = &imx_pops,
                .line           = 0,
        },
@@ -690,7 +690,7 @@ static struct imx_port imx_ports[] = {
                .irq            = UART2_MINT_RX,
                .uartclk        = 16000000,
                .fifosize       = 8,
-               .flags          = ASYNC_BOOT_AUTOCONF,
+               .flags          = UPF_BOOT_AUTOCONF,
                .ops            = &imx_pops,
                .line           = 1,
        },
index eb4883efb7c65953534797dc913752d5dbcefddf..0a2dd6c5b95fdecc116e78a4090552e31be90eaa 100644 (file)
@@ -1060,7 +1060,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
        dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
 
        port->mapbase   = res->start;
-       port->membase   = S3C24XX_VA_UART + (res->start - S3C2410_PA_UART);
+       port->membase   = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
        port->irq       = platform_get_irq(platdev, 0);
 
        ourport->clk    = clk_get(&platdev->dev, "uart");
index 1bd93168f504117440acf790f2e0bfbe384d6c5c..ff7b60b4de37171d116bf34d2b9a5abf36cf5926 100644 (file)
@@ -665,21 +665,21 @@ void __init sa1100_register_uart(int idx, int port)
                sa1100_ports[idx].port.membase = (void __iomem *)&Ser1UTCR0;
                sa1100_ports[idx].port.mapbase = _Ser1UTCR0;
                sa1100_ports[idx].port.irq     = IRQ_Ser1UART;
-               sa1100_ports[idx].port.flags   = ASYNC_BOOT_AUTOCONF;
+               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
                break;
 
        case 2:
                sa1100_ports[idx].port.membase = (void __iomem *)&Ser2UTCR0;
                sa1100_ports[idx].port.mapbase = _Ser2UTCR0;
                sa1100_ports[idx].port.irq     = IRQ_Ser2ICP;
-               sa1100_ports[idx].port.flags   = ASYNC_BOOT_AUTOCONF;
+               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
                break;
 
        case 3:
                sa1100_ports[idx].port.membase = (void __iomem *)&Ser3UTCR0;
                sa1100_ports[idx].port.mapbase = _Ser3UTCR0;
                sa1100_ports[idx].port.irq     = IRQ_Ser3UART;
-               sa1100_ports[idx].port.flags   = ASYNC_BOOT_AUTOCONF;
+               sa1100_ports[idx].port.flags   = UPF_BOOT_AUTOCONF;
                break;
 
        default:
index 943770470b9db316af2ed25cce1fca9296df43a2..0717abfdae06f1eed3d132cdbd7e7a3cced60858 100644 (file)
@@ -332,7 +332,7 @@ uart_get_baud_rate(struct uart_port *port, struct termios *termios,
                   struct termios *old, unsigned int min, unsigned int max)
 {
        unsigned int try, baud, altbaud = 38400;
-       unsigned int flags = port->flags & UPF_SPD_MASK;
+       upf_t flags = port->flags & UPF_SPD_MASK;
 
        if (flags == UPF_SPD_HI)
                altbaud = 57600;
@@ -615,8 +615,9 @@ static int uart_set_info(struct uart_state *state,
        struct serial_struct new_serial;
        struct uart_port *port = state->port;
        unsigned long new_port;
-       unsigned int change_irq, change_port, old_flags, closing_wait;
+       unsigned int change_irq, change_port, closing_wait;
        unsigned int old_custom_divisor, close_delay;
+       upf_t old_flags, new_flags;
        int retval = 0;
 
        if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
@@ -655,6 +656,7 @@ static int uart_set_info(struct uart_state *state,
                      new_serial.type != port->type;
 
        old_flags = port->flags;
+       new_flags = new_serial.flags;
        old_custom_divisor = port->custom_divisor;
 
        if (!capable(CAP_SYS_ADMIN)) {
@@ -664,10 +666,10 @@ static int uart_set_info(struct uart_state *state,
                    (close_delay != state->close_delay) ||
                    (closing_wait != state->closing_wait) ||
                    (new_serial.xmit_fifo_size != port->fifosize) ||
-                   (((new_serial.flags ^ old_flags) & ~UPF_USR_MASK) != 0))
+                   (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
                        goto exit;
                port->flags = ((port->flags & ~UPF_USR_MASK) |
-                              (new_serial.flags & UPF_USR_MASK));
+                              (new_flags & UPF_USR_MASK));
                port->custom_divisor = new_serial.custom_divisor;
                goto check_and_exit;
        }
@@ -764,7 +766,7 @@ static int uart_set_info(struct uart_state *state,
        port->irq              = new_serial.irq;
        port->uartclk          = new_serial.baud_base * 16;
        port->flags            = (port->flags & ~UPF_CHANGE_MASK) |
-                                (new_serial.flags & UPF_CHANGE_MASK);
+                                (new_flags & UPF_CHANGE_MASK);
        port->custom_divisor   = new_serial.custom_divisor;
        state->close_delay     = close_delay;
        state->closing_wait    = closing_wait;
@@ -1870,7 +1872,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
        mutex_lock(&state->mutex);
 
        if (state->info && state->info->flags & UIF_INITIALIZED) {
-               struct uart_ops *ops = port->ops;
+               const struct uart_ops *ops = port->ops;
 
                spin_lock_irq(&port->lock);
                ops->stop_tx(port);
@@ -1932,7 +1934,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
        }
 
        if (state->info && state->info->flags & UIF_INITIALIZED) {
-               struct uart_ops *ops = port->ops;
+               const struct uart_ops *ops = port->ops;
                int ret;
 
                ops->set_mctrl(port, 0);
index d4a1f0e798c1bc461f737ec343e92d196608183f..d0490f67f597fa1be96f0271be6b99339216339b 100644 (file)
@@ -506,7 +506,7 @@ static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
                        .uartclk        = 14745600/2,
                        .fifosize       = 16,
                        .ops            = &lh7a40x_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
        },
@@ -519,7 +519,7 @@ static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
                        .uartclk        = 14745600/2,
                        .fifosize       = 16,
                        .ops            = &lh7a40x_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 1,
                },
        },
@@ -532,7 +532,7 @@ static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
                        .uartclk        = 14745600/2,
                        .fifosize       = 16,
                        .ops            = &lh7a40x_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 2,
                },
        },
index a9e070759628558c970487fa48209d40139aa4ef..0111206327cac4505c2469cd326b7b09ba490fbf 100644 (file)
@@ -1113,10 +1113,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xfffffe80,
                        .mapbase        = 0xfffffe80,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 25,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCI,
@@ -1128,10 +1128,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)SCIF0,
                        .mapbase        = SCIF0,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 55,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCIF,
@@ -1142,10 +1142,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)SCIF2,
                        .mapbase        = SCIF2,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 59,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 1,
                },
                .type           = PORT_SCIF,
@@ -1157,10 +1157,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xfffffe80,
                        .mapbase        = 0xfffffe80,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 25,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCI,
@@ -1171,10 +1171,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xa4000150,
                        .mapbase        = 0xa4000150,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 59,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 1,
                },
                .type           = PORT_SCIF,
@@ -1185,10 +1185,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xa4000140,
                        .mapbase        = 0xa4000140,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 55,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 2,
                },
                .type           = PORT_IRDA,
@@ -1200,10 +1200,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xA4430000,
                        .mapbase        = 0xA4430000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 25,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCIF,
@@ -1215,10 +1215,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xffe00000,
                        .mapbase        = 0xffe00000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 25,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCIF,
@@ -1230,10 +1230,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xffe80000,
                        .mapbase        = 0xffe80000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 43,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCIF,
@@ -1245,10 +1245,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xffe00000,
                        .mapbase        = 0xffe00000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 25,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCI,
@@ -1259,10 +1259,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xffe80000,
                        .mapbase        = 0xffe80000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 43,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 1,
                },
                .type           = PORT_SCIF,
@@ -1274,10 +1274,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xfe600000,
                        .mapbase        = 0xfe600000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 55,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCIF,
@@ -1288,10 +1288,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xfe610000,
                        .mapbase        = 0xfe610000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 75,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 1,
                },
                .type           = PORT_SCIF,
@@ -1302,10 +1302,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xfe620000,
                        .mapbase        = 0xfe620000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 79,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 2,
                },
                .type           = PORT_SCIF,
@@ -1317,10 +1317,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xffe80000,
                        .mapbase        = 0xffe80000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 43,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCIF,
@@ -1332,10 +1332,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xffe00000,
                        .mapbase        = 0xffe00000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 26,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCIF,
@@ -1346,10 +1346,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0xffe80000,
                        .mapbase        = 0xffe80000,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 43,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 1,
                },
                .type           = PORT_SCIF,
@@ -1359,10 +1359,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
 #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
        {
                .port   = {
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 42,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCIF,
@@ -1374,10 +1374,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0x00ffffb0,
                        .mapbase        = 0x00ffffb0,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 54,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCI,
@@ -1388,10 +1388,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0x00ffffb8,
                        .mapbase        = 0x00ffffb8,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 58,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 1,
                },
                .type           = PORT_SCI,
@@ -1402,10 +1402,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0x00ffffc0,
                        .mapbase        = 0x00ffffc0,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 62,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 2,
                },
                .type           = PORT_SCI,
@@ -1417,10 +1417,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0x00ffff78,
                        .mapbase        = 0x00ffff78,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 90,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 0,
                },
                .type           = PORT_SCI,
@@ -1431,10 +1431,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0x00ffff80,
                        .mapbase        = 0x00ffff80,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 94,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 1,
                },
                .type           = PORT_SCI,
@@ -1445,10 +1445,10 @@ static struct sci_port sci_ports[SCI_NPORTS] = {
                .port   = {
                        .membase        = (void *)0x00ffff88,
                        .mapbase        = 0x00ffff88,
-                       .iotype         = SERIAL_IO_MEM,
+                       .iotype         = UPIO_MEM,
                        .irq            = 98,
                        .ops            = &sci_uart_ops,
-                       .flags          = ASYNC_BOOT_AUTOCONF,
+                       .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 2,
                },
                .type           = PORT_SCI,
index 9a3665b34d97218dca97b18bbf60740bb45dece7..bc67442c6b4ce92f227cf62c81b7f507c11cb6e5 100644 (file)
@@ -669,7 +669,7 @@ static int sunsu_startup(struct uart_port *port)
         * if it is, then bail out, because there's likely no UART
         * here.
         */
-       if (!(up->port.flags & ASYNC_BUGGY_UART) &&
+       if (!(up->port.flags & UPF_BUGGY_UART) &&
            (serial_inp(up, UART_LSR) == 0xff)) {
                printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
                return -ENODEV;
@@ -707,7 +707,7 @@ static int sunsu_startup(struct uart_port *port)
        up->ier = UART_IER_RLSI | UART_IER_RDI;
        serial_outp(up, UART_IER, up->ier);
 
-       if (up->port.flags & ASYNC_FOURPORT) {
+       if (up->port.flags & UPF_FOURPORT) {
                unsigned int icp;
                /*
                 * Enable interrupts on the AST Fourport board
@@ -740,7 +740,7 @@ static void sunsu_shutdown(struct uart_port *port)
        serial_outp(up, UART_IER, 0);
 
        spin_lock_irqsave(&up->port.lock, flags);
-       if (up->port.flags & ASYNC_FOURPORT) {
+       if (up->port.flags & UPF_FOURPORT) {
                /* reset interrupts on the AST Fourport board */
                inb((up->port.iobase & 0xfe0) | 0x1f);
                up->port.mctrl |= TIOCM_OUT1;
@@ -1132,7 +1132,7 @@ ebus_done:
 
        spin_lock_irqsave(&up->port.lock, flags);
 
-       if (!(up->port.flags & ASYNC_BUGGY_UART)) {
+       if (!(up->port.flags & UPF_BUGGY_UART)) {
                /*
                 * Do a simple existence test first; if we fail this, there's
                 * no point trying anything else.
@@ -1170,7 +1170,7 @@ ebus_done:
         * manufacturer would be stupid enough to design a board
         * that conflicts with COM 1-4 --- we hope!
         */
-       if (!(up->port.flags & ASYNC_SKIP_TEST)) {
+       if (!(up->port.flags & UPF_SKIP_TEST)) {
                serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
                status1 = serial_inp(up, UART_MSR) & 0xF0;
                serial_outp(up, UART_MCR, save_mcr);
@@ -1371,7 +1371,7 @@ static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up)
        } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
 
        /* Wait up to 1s for flow control if necessary */
-       if (up->port.flags & ASYNC_CONS_FLOW) {
+       if (up->port.flags & UPF_CONS_FLOW) {
                tmout = 1000000;
                while (--tmout &&
                       ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
@@ -1513,7 +1513,7 @@ static int __init sunsu_serial_init(void)
                    up->su_type == SU_PORT_KBD)
                        continue;
 
-               up->port.flags |= ASYNC_BOOT_AUTOCONF;
+               up->port.flags |= UPF_BOOT_AUTOCONF;
                up->port.type = PORT_UNKNOWN;
                up->port.uartclk = (SU_BASE_BAUD * 16);
 
index 3639c3f8d3578f0fdb9fa5841ed04a410f379b99..36e476dd912388d0257ccdd82c15af888c5e8256 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_USB_XPAD)                += input/
 
 obj-$(CONFIG_USB_DABUSB)       += media/
 obj-$(CONFIG_USB_DSBR)         += media/
+obj-$(CONFIG_USB_ET61X251)     += media/
 obj-$(CONFIG_USB_IBMCAM)       += media/
 obj-$(CONFIG_USB_KONICAWC)     += media/
 obj-$(CONFIG_USB_OV511)                += media/
index af0a41e7870e0955eaf04e4e63608be04150982d..04631dcbabbce2673529aeffc7e16131d796d817 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/init.h>
 #include <linux/device.h>      /* FIXME: linux/firmware.h should include it itself */
 #include <linux/firmware.h>
+#include <linux/mutex.h>
 
 #include "usbatm.h"
 
@@ -160,7 +161,7 @@ struct cxacru_data {
        struct work_struct poll_work;
 
        /* contol handles */
-       struct semaphore cm_serialize;
+       struct mutex cm_serialize;
        u8 *rcv_buf;
        u8 *snd_buf;
        struct urb *rcv_urb;
@@ -219,7 +220,7 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
                goto fail;
        }
 
-       down(&instance->cm_serialize);
+       mutex_lock(&instance->cm_serialize);
 
        /* submit reading urb before the writing one */
        init_completion(&instance->rcv_done);
@@ -288,7 +289,7 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
        ret = offd;
        dbg("cm %#x", cm);
 fail:
-       up(&instance->cm_serialize);
+       mutex_unlock(&instance->cm_serialize);
        return ret;
 }
 
@@ -352,7 +353,6 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
                struct atm_dev *atm_dev)
 {
        struct cxacru_data *instance = usbatm_instance->driver_data;
-       struct device *dev = &usbatm_instance->usb_intf->dev;
        /*
        struct atm_dev *atm_dev = usbatm_instance->atm_dev;
        */
@@ -364,14 +364,14 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
        ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0,
                        atm_dev->esi, sizeof(atm_dev->esi));
        if (ret < 0) {
-               dev_err(dev, "cxacru_atm_start: CARD_GET_MAC_ADDRESS returned %d\n", ret);
+               atm_err(usbatm_instance, "cxacru_atm_start: CARD_GET_MAC_ADDRESS returned %d\n", ret);
                return ret;
        }
 
        /* start ADSL */
        ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
        if (ret < 0) {
-               dev_err(dev, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret);
+               atm_err(usbatm_instance, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret);
                return ret;
        }
 
@@ -383,13 +383,13 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
 static void cxacru_poll_status(struct cxacru_data *instance)
 {
        u32 buf[CXINF_MAX] = {};
-       struct device *dev = &instance->usbatm->usb_intf->dev;
-       struct atm_dev *atm_dev = instance->usbatm->atm_dev;
+       struct usbatm_data *usbatm = instance->usbatm;
+       struct atm_dev *atm_dev = usbatm->atm_dev;
        int ret;
 
        ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX);
        if (ret < 0) {
-               dev_warn(dev, "poll status: error %d\n", ret);
+               atm_warn(usbatm, "poll status: error %d\n", ret);
                goto reschedule;
        }
 
@@ -400,50 +400,50 @@ static void cxacru_poll_status(struct cxacru_data *instance)
        switch (instance->line_status) {
        case 0:
                atm_dev->signal = ATM_PHY_SIG_LOST;
-               dev_info(dev, "ADSL line: down\n");
+               atm_info(usbatm, "ADSL line: down\n");
                break;
 
        case 1:
                atm_dev->signal = ATM_PHY_SIG_LOST;
-               dev_info(dev, "ADSL line: attemtping to activate\n");
+               atm_info(usbatm, "ADSL line: attempting to activate\n");
                break;
 
        case 2:
                atm_dev->signal = ATM_PHY_SIG_LOST;
-               dev_info(dev, "ADSL line: training\n");
+               atm_info(usbatm, "ADSL line: training\n");
                break;
 
        case 3:
                atm_dev->signal = ATM_PHY_SIG_LOST;
-               dev_info(dev, "ADSL line: channel analysis\n");
+               atm_info(usbatm, "ADSL line: channel analysis\n");
                break;
 
        case 4:
                atm_dev->signal = ATM_PHY_SIG_LOST;
-               dev_info(dev, "ADSL line: exchange\n");
+               atm_info(usbatm, "ADSL line: exchange\n");
                break;
 
        case 5:
                atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424;
                atm_dev->signal = ATM_PHY_SIG_FOUND;
 
-               dev_info(dev, "ADSL line: up (%d kb/s down | %d kb/s up)\n",
+               atm_info(usbatm, "ADSL line: up (%d kb/s down | %d kb/s up)\n",
                     buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]);
                break;
 
        case 6:
                atm_dev->signal = ATM_PHY_SIG_LOST;
-               dev_info(dev, "ADSL line: waiting\n");
+               atm_info(usbatm, "ADSL line: waiting\n");
                break;
 
        case 7:
                atm_dev->signal = ATM_PHY_SIG_LOST;
-               dev_info(dev, "ADSL line: initializing\n");
+               atm_info(usbatm, "ADSL line: initializing\n");
                break;
 
        default:
                atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
-               dev_info(dev, "Unknown line state %02x\n", instance->line_status);
+               atm_info(usbatm, "Unknown line state %02x\n", instance->line_status);
                break;
        }
 reschedule:
@@ -504,8 +504,8 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
 {
        int ret;
        int off;
-       struct usb_device *usb_dev = instance->usbatm->usb_dev;
-       struct device *dev = &instance->usbatm->usb_intf->dev;
+       struct usbatm_data *usbatm = instance->usbatm;
+       struct usb_device *usb_dev = usbatm->usb_dev;
        u16 signature[] = { usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct };
        u32 val;
 
@@ -515,7 +515,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
        val = cpu_to_le32(instance->modem_type->pll_f_clk);
        ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4);
        if (ret) {
-               dev_err(dev, "FirmwarePllFClkValue failed: %d\n", ret);
+               usb_err(usbatm, "FirmwarePllFClkValue failed: %d\n", ret);
                return;
        }
 
@@ -523,7 +523,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
        val = cpu_to_le32(instance->modem_type->pll_b_clk);
        ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4);
        if (ret) {
-               dev_err(dev, "FirmwarePllBClkValue failed: %d\n", ret);
+               usb_err(usbatm, "FirmwarePllBClkValue failed: %d\n", ret);
                return;
        }
 
@@ -531,14 +531,14 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
        val = cpu_to_le32(SDRAM_ENA);
        ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4);
        if (ret) {
-               dev_err(dev, "Enable SDRAM failed: %d\n", ret);
+               usb_err(usbatm, "Enable SDRAM failed: %d\n", ret);
                return;
        }
 
        /* Firmware */
        ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size);
        if (ret) {
-               dev_err(dev, "Firmware upload failed: %d\n", ret);
+               usb_err(usbatm, "Firmware upload failed: %d\n", ret);
                return;
        }
 
@@ -546,7 +546,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
        if (instance->modem_type->boot_rom_patch) {
                ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size);
                if (ret) {
-                       dev_err(dev, "Boot ROM patching failed: %d\n", ret);
+                       usb_err(usbatm, "Boot ROM patching failed: %d\n", ret);
                        return;
                }
        }
@@ -554,7 +554,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
        /* Signature */
        ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4);
        if (ret) {
-               dev_err(dev, "Signature storing failed: %d\n", ret);
+               usb_err(usbatm, "Signature storing failed: %d\n", ret);
                return;
        }
 
@@ -566,7 +566,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
                ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0);
        }
        if (ret) {
-               dev_err(dev, "Passing control to firmware failed: %d\n", ret);
+               usb_err(usbatm, "Passing control to firmware failed: %d\n", ret);
                return;
        }
 
@@ -580,7 +580,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
 
        ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
        if (ret < 0) {
-               dev_err(dev, "modem failed to initialize: %d\n", ret);
+               usb_err(usbatm, "modem failed to initialize: %d\n", ret);
                return;
        }
 
@@ -597,7 +597,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
                        ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
                                        (u8 *) buf, len, NULL, 0);
                        if (ret < 0) {
-                               dev_err(dev, "load config data failed: %d\n", ret);
+                               usb_err(usbatm, "load config data failed: %d\n", ret);
                                return;
                        }
                }
@@ -608,18 +608,19 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
 static int cxacru_find_firmware(struct cxacru_data *instance,
                                char* phase, const struct firmware **fw_p)
 {
-       struct device *dev = &instance->usbatm->usb_intf->dev;
+       struct usbatm_data *usbatm = instance->usbatm;
+       struct device *dev = &usbatm->usb_intf->dev;
        char buf[16];
 
        sprintf(buf, "cxacru-%s.bin", phase);
        dbg("cxacru_find_firmware: looking for %s", buf);
 
        if (request_firmware(fw_p, buf, dev)) {
-               dev_dbg(dev, "no stage %s firmware found\n", phase);
+               usb_dbg(usbatm, "no stage %s firmware found\n", phase);
                return -ENOENT;
        }
 
-       dev_info(dev, "found firmware %s\n", buf);
+       usb_info(usbatm, "found firmware %s\n", buf);
 
        return 0;
 }
@@ -627,20 +628,19 @@ static int cxacru_find_firmware(struct cxacru_data *instance,
 static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
                             struct usb_interface *usb_intf)
 {
-       struct device *dev = &usbatm_instance->usb_intf->dev;
        const struct firmware *fw, *bp, *cf;
        struct cxacru_data *instance = usbatm_instance->driver_data;
 
        int ret = cxacru_find_firmware(instance, "fw", &fw);
        if (ret) {
-               dev_warn(dev, "firmware (cxacru-fw.bin) unavailable (hotplug misconfiguration?)\n");
+               usb_warn(usbatm_instance, "firmware (cxacru-fw.bin) unavailable (system misconfigured?)\n");
                return ret;
        }
 
        if (instance->modem_type->boot_rom_patch) {
                ret = cxacru_find_firmware(instance, "bp", &bp);
                if (ret) {
-                       dev_warn(dev, "boot ROM patch (cxacru-bp.bin) unavailable (hotplug misconfiguration?)\n");
+                       usb_warn(usbatm_instance, "boot ROM patch (cxacru-bp.bin) unavailable (system misconfigured?)\n");
                        release_firmware(fw);
                        return ret;
                }
@@ -667,22 +667,19 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
 }
 
 static int cxacru_bind(struct usbatm_data *usbatm_instance,
-                      struct usb_interface *intf, const struct usb_device_id *id,
-                      int *need_heavy_init)
+                      struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct cxacru_data *instance;
        struct usb_device *usb_dev = interface_to_usbdev(intf);
        int ret;
 
        /* instance init */
-       instance = kmalloc(sizeof(*instance), GFP_KERNEL);
+       instance = kzalloc(sizeof(*instance), GFP_KERNEL);
        if (!instance) {
                dbg("cxacru_bind: no memory for instance data");
                return -ENOMEM;
        }
 
-       memset(instance, 0, sizeof(*instance));
-
        instance->usbatm = usbatm_instance;
        instance->modem_type = (struct cxacru_modem_type *) id->driver_info;
 
@@ -721,13 +718,13 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
                        instance->snd_buf, PAGE_SIZE,
                        cxacru_blocking_completion, &instance->snd_done, 4);
 
-       init_MUTEX(&instance->cm_serialize);
+       mutex_init(&instance->cm_serialize);
 
        INIT_WORK(&instance->poll_work, (void *)cxacru_poll_status, instance);
 
        usbatm_instance->driver_data = instance;
 
-       *need_heavy_init = cxacru_card_status(instance);
+       usbatm_instance->flags = (cxacru_card_status(instance) ? 0 : UDSL_SKIP_HEAVY_INIT);
 
        return 0;
 
@@ -787,12 +784,12 @@ static const struct usb_device_id cxacru_usb_ids[] = {
        { /* V = Conexant                       P = ADSL modem (Hasbani project)        */
                USB_DEVICE(0x0572, 0xcb00),     .driver_info = (unsigned long) &cxacru_cb00
        },
-       { /* V = Conexant             P = ADSL modem (Well PTI-800 */
-               USB_DEVICE(0x0572, 0xcb02),     .driver_info = (unsigned long) &cxacru_cb00
-       },
        { /* V = Conexant                       P = ADSL modem                          */
                USB_DEVICE(0x0572, 0xcb01),     .driver_info = (unsigned long) &cxacru_cb00
        },
+       { /* V = Conexant                       P = ADSL modem (Well PTI-800) */
+               USB_DEVICE(0x0572, 0xcb02),     .driver_info = (unsigned long) &cxacru_cb00
+       },
        { /* V = Conexant                       P = ADSL modem                          */
                USB_DEVICE(0x0572, 0xcb06),     .driver_info = (unsigned long) &cxacru_cb00
        },
@@ -835,14 +832,13 @@ static const struct usb_device_id cxacru_usb_ids[] = {
 MODULE_DEVICE_TABLE(usb, cxacru_usb_ids);
 
 static struct usbatm_driver cxacru_driver = {
-       .owner          = THIS_MODULE,
        .driver_name    = cxacru_driver_name,
        .bind           = cxacru_bind,
        .heavy_init     = cxacru_heavy_init,
        .unbind         = cxacru_unbind,
        .atm_start      = cxacru_atm_start,
-       .in             = CXACRU_EP_DATA,
-       .out            = CXACRU_EP_DATA,
+       .bulk_in        = CXACRU_EP_DATA,
+       .bulk_out       = CXACRU_EP_DATA,
        .rx_padding     = 3,
        .tx_padding     = 11,
 };
index c1b47d74e206a468fdc9c2bce7792d19740256e1..7860c8a5800d5a184adc8abea047dbef16c37b89 100644 (file)
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/usb_ch9.h>
 #include <linux/workqueue.h>
 
 #include "usbatm.h"
 
 #define DRIVER_AUTHOR  "Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
-#define DRIVER_VERSION "1.9"
+#define DRIVER_VERSION "1.10"
 #define DRIVER_DESC    "Alcatel SpeedTouch USB driver version " DRIVER_VERSION
 
 static const char speedtch_driver_name[] = "speedtch";
@@ -66,31 +68,42 @@ static const char speedtch_driver_name[] = "speedtch";
 
 #define RESUBMIT_DELAY         1000    /* milliseconds */
 
-#define DEFAULT_ALTSETTING     1
+#define DEFAULT_BULK_ALTSETTING        1
+#define DEFAULT_ISOC_ALTSETTING        2
 #define DEFAULT_DL_512_FIRST   0
+#define DEFAULT_ENABLE_ISOC    0
 #define DEFAULT_SW_BUFFERING   0
 
-static int altsetting = DEFAULT_ALTSETTING;
+static unsigned int altsetting = 0; /* zero means: use the default */
 static int dl_512_first = DEFAULT_DL_512_FIRST;
+static int enable_isoc = DEFAULT_ENABLE_ISOC;
 static int sw_buffering = DEFAULT_SW_BUFFERING;
 
-module_param(altsetting, int, S_IRUGO | S_IWUSR);
+module_param(altsetting, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(altsetting,
-                "Alternative setting for data interface (default: "
-                __MODULE_STRING(DEFAULT_ALTSETTING) ")");
+               "Alternative setting for data interface (bulk_default: "
+               __MODULE_STRING(DEFAULT_BULK_ALTSETTING) "; isoc_default: "
+               __MODULE_STRING(DEFAULT_ISOC_ALTSETTING) ")");
 
 module_param(dl_512_first, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(dl_512_first,
                 "Read 512 bytes before sending firmware (default: "
                 __MODULE_STRING(DEFAULT_DL_512_FIRST) ")");
 
+module_param(enable_isoc, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(enable_isoc,
+               "Use isochronous transfers if available (default: "
+               __MODULE_STRING(DEFAULT_ENABLE_ISOC) ")");
+
 module_param(sw_buffering, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(sw_buffering,
                 "Enable software buffering (default: "
                 __MODULE_STRING(DEFAULT_SW_BUFFERING) ")");
 
+#define INTERFACE_DATA         1
 #define ENDPOINT_INT           0x81
-#define ENDPOINT_DATA          0x07
+#define ENDPOINT_BULK_DATA     0x07
+#define ENDPOINT_ISOC_DATA     0x07
 #define ENDPOINT_FIRMWARE      0x05
 
 #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
@@ -98,6 +111,8 @@ MODULE_PARM_DESC(sw_buffering,
 struct speedtch_instance_data {
        struct usbatm_data *usbatm;
 
+       unsigned int altsetting;
+
        struct work_struct status_checker;
 
        unsigned char last_status;
@@ -205,7 +220,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
                                   buffer, 0x200, &actual_length, 2000);
 
                if (ret < 0 && ret != -ETIMEDOUT)
-                       usb_dbg(usbatm, "%s: read BLOCK0 from modem failed (%d)!\n", __func__, ret);
+                       usb_warn(usbatm, "%s: read BLOCK0 from modem failed (%d)!\n", __func__, ret);
                else
                        usb_dbg(usbatm, "%s: BLOCK0 downloaded (%d bytes)\n", __func__, ret);
        }
@@ -219,7 +234,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
                                   buffer, thislen, &actual_length, DATA_TIMEOUT);
 
                if (ret < 0) {
-                       usb_dbg(usbatm, "%s: write BLOCK1 to modem failed (%d)!\n", __func__, ret);
+                       usb_err(usbatm, "%s: write BLOCK1 to modem failed (%d)!\n", __func__, ret);
                        goto out_free;
                }
                usb_dbg(usbatm, "%s: BLOCK1 uploaded (%zu bytes)\n", __func__, fw1->size);
@@ -232,7 +247,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
                           buffer, 0x200, &actual_length, DATA_TIMEOUT);
 
        if (ret < 0) {
-               usb_dbg(usbatm, "%s: read BLOCK2 from modem failed (%d)!\n", __func__, ret);
+               usb_err(usbatm, "%s: read BLOCK2 from modem failed (%d)!\n", __func__, ret);
                goto out_free;
        }
        usb_dbg(usbatm, "%s: BLOCK2 downloaded (%d bytes)\n", __func__, actual_length);
@@ -246,7 +261,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
                                   buffer, thislen, &actual_length, DATA_TIMEOUT);
 
                if (ret < 0) {
-                       usb_dbg(usbatm, "%s: write BLOCK3 to modem failed (%d)!\n", __func__, ret);
+                       usb_err(usbatm, "%s: write BLOCK3 to modem failed (%d)!\n", __func__, ret);
                        goto out_free;
                }
        }
@@ -259,7 +274,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
                           buffer, 0x200, &actual_length, DATA_TIMEOUT);
 
        if (ret < 0) {
-               usb_dbg(usbatm, "%s: read BLOCK4 from modem failed (%d)!\n", __func__, ret);
+               usb_err(usbatm, "%s: read BLOCK4 from modem failed (%d)!\n", __func__, ret);
                goto out_free;
        }
 
@@ -270,6 +285,11 @@ 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);
+               goto out_free;
+       }
+
        /* Enable software buffering, if requested */
        if (sw_buffering)
                speedtch_set_swbuff(instance, 1);
@@ -285,8 +305,8 @@ out:
        return ret;
 }
 
-static int speedtch_find_firmware(struct usb_interface *intf, int phase,
-                                 const struct firmware **fw_p)
+static int speedtch_find_firmware(struct usbatm_data *usbatm, struct usb_interface *intf,
+                                 int phase, const struct firmware **fw_p)
 {
        struct device *dev = &intf->dev;
        const u16 bcdDevice = le16_to_cpu(interface_to_usbdev(intf)->descriptor.bcdDevice);
@@ -295,24 +315,24 @@ static int speedtch_find_firmware(struct usb_interface *intf, int phase,
        char buf[24];
 
        sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision);
-       dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
+       usb_dbg(usbatm, "%s: looking for %s\n", __func__, buf);
 
        if (request_firmware(fw_p, buf, dev)) {
                sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision);
-               dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
+               usb_dbg(usbatm, "%s: looking for %s\n", __func__, buf);
 
                if (request_firmware(fw_p, buf, dev)) {
                        sprintf(buf, "speedtch-%d.bin", phase);
-                       dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
+                       usb_dbg(usbatm, "%s: looking for %s\n", __func__, buf);
 
                        if (request_firmware(fw_p, buf, dev)) {
-                               dev_warn(dev, "no stage %d firmware found!\n", phase);
+                               usb_err(usbatm, "%s: no stage %d firmware found!\n", __func__, phase);
                                return -ENOENT;
                        }
                }
        }
 
-       dev_info(dev, "found stage %d firmware %s\n", phase, buf);
+       usb_info(usbatm, "found stage %d firmware %s\n", phase, buf);
 
        return 0;
 }
@@ -323,15 +343,16 @@ static int speedtch_heavy_init(struct usbatm_data *usbatm, struct usb_interface
        struct speedtch_instance_data *instance = usbatm->driver_data;
        int ret;
 
-       if ((ret = speedtch_find_firmware(intf, 1, &fw1)) < 0)
-                       return ret;
+       if ((ret = speedtch_find_firmware(usbatm, intf, 1, &fw1)) < 0)
+               return ret;
 
-       if ((ret = speedtch_find_firmware(intf, 2, &fw2)) < 0) {
+       if ((ret = speedtch_find_firmware(usbatm, intf, 2, &fw2)) < 0) {
                release_firmware(fw1);
                return ret;
        }
 
-       ret = speedtch_upload_firmware(instance, fw1, fw2);
+       if ((ret = speedtch_upload_firmware(instance, fw1, fw2)) < 0)
+               usb_err(usbatm, "%s: firmware upload failed (%d)!\n", __func__, ret);
 
        release_firmware(fw2);
        release_firmware(fw1);
@@ -428,7 +449,9 @@ static void speedtch_check_status(struct speedtch_instance_data *instance)
        int down_speed, up_speed, ret;
        unsigned char status;
 
+#ifdef VERBOSE_DEBUG
        atm_dbg(usbatm, "%s entered\n", __func__);
+#endif
 
        ret = speedtch_read_status(instance);
        if (ret < 0) {
@@ -441,9 +464,9 @@ static void speedtch_check_status(struct speedtch_instance_data *instance)
 
        status = buf[OFFSET_7];
 
-       atm_dbg(usbatm, "%s: line state %02x\n", __func__, status);
-
        if ((status != instance->last_status) || !status) {
+               atm_dbg(usbatm, "%s: line state 0x%02x\n", __func__, status);
+
                switch (status) {
                case 0:
                        atm_dev->signal = ATM_PHY_SIG_LOST;
@@ -484,7 +507,7 @@ static void speedtch_check_status(struct speedtch_instance_data *instance)
 
                default:
                        atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
-                       atm_info(usbatm, "Unknown line state %02x\n", status);
+                       atm_info(usbatm, "unknown line state %02x\n", status);
                        break;
                }
 
@@ -583,11 +606,6 @@ static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_de
 
        atm_dbg(usbatm, "%s entered\n", __func__);
 
-       if ((ret = usb_set_interface(usb_dev, 1, altsetting)) < 0) {
-               atm_dbg(usbatm, "%s: usb_set_interface returned %d!\n", __func__, ret);
-               return ret;
-       }
-
        /* Set MAC address, it is stored in the serial number */
        memset(atm_dev->esi, 0, sizeof(atm_dev->esi));
        if (usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {
@@ -678,20 +696,27 @@ static void speedtch_release_interfaces(struct usb_device *usb_dev, int num_inte
 
 static int speedtch_bind(struct usbatm_data *usbatm,
                         struct usb_interface *intf,
-                        const struct usb_device_id *id,
-                        int *need_heavy_init)
+                        const struct usb_device_id *id)
 {
        struct usb_device *usb_dev = interface_to_usbdev(intf);
-       struct usb_interface *cur_intf;
+       struct usb_interface *cur_intf, *data_intf;
        struct speedtch_instance_data *instance;
        int ifnum = intf->altsetting->desc.bInterfaceNumber;
        int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces;
        int i, ret;
+       int use_isoc;
 
        usb_dbg(usbatm, "%s entered\n", __func__);
 
+       /* sanity checks */
+
        if (usb_dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
-               usb_dbg(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass);
+               usb_err(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass);
+               return -ENODEV;
+       }
+
+       if (!(data_intf = usb_ifnum_to_if(usb_dev, INTERFACE_DATA))) {
+               usb_err(usbatm, "%s: data interface not found!\n", __func__);
                return -ENODEV;
        }
 
@@ -704,25 +729,71 @@ static int speedtch_bind(struct usbatm_data *usbatm,
                        ret = usb_driver_claim_interface(&speedtch_usb_driver, cur_intf, usbatm);
 
                        if (ret < 0) {
-                               usb_dbg(usbatm, "%s: failed to claim interface %d (%d)\n", __func__, i, ret);
+                               usb_err(usbatm, "%s: failed to claim interface %2d (%d)!\n", __func__, i, ret);
                                speedtch_release_interfaces(usb_dev, i);
                                return ret;
                        }
                }
        }
 
-       instance = kmalloc(sizeof(*instance), GFP_KERNEL);
+       instance = kzalloc(sizeof(*instance), GFP_KERNEL);
 
        if (!instance) {
-               usb_dbg(usbatm, "%s: no memory for instance data!\n", __func__);
+               usb_err(usbatm, "%s: no memory for instance data!\n", __func__);
                ret = -ENOMEM;
                goto fail_release;
        }
 
-       memset(instance, 0, sizeof(struct speedtch_instance_data));
-
        instance->usbatm = usbatm;
 
+       /* altsetting and enable_isoc may change at any moment, so take a snapshot */
+       instance->altsetting = altsetting;
+       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->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 */
+               }
+
+       if (use_isoc) {
+               const struct usb_host_interface *desc = data_intf->cur_altsetting;
+               const __u8 target_address = USB_DIR_IN | usbatm->driver->isoc_in;
+               int i;
+
+               use_isoc = 0; /* fall back to bulk if endpoint not found */
+
+               for (i=0; i<desc->desc.bNumEndpoints; i++) {
+                       const struct usb_endpoint_descriptor *endpoint_desc = &desc->endpoint[i].desc;
+
+                       if ((endpoint_desc->bEndpointAddress == target_address)) {
+                               use_isoc = (endpoint_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+                                       USB_ENDPOINT_XFER_ISOC;
+                               break;
+                       }
+               }
+
+               if (!use_isoc)
+                       usb_info(usbatm, "isochronous transfer not supported - using bulk\n");
+       }
+
+       if (!use_isoc && !instance->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;
+
+       usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0);
+
        INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance);
 
        instance->status_checker.timer.function = speedtch_status_poll;
@@ -749,13 +820,15 @@ static int speedtch_bind(struct usbatm_data *usbatm,
                              0x12, 0xc0, 0x07, 0x00,
                              instance->scratch_buffer + OFFSET_7, SIZE_7, 500);
 
-       *need_heavy_init = (ret != SIZE_7);
+       usbatm->flags |= (ret == SIZE_7 ? UDSL_SKIP_HEAVY_INIT : 0);
 
-       usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, need_heavy_init ? "not" : "already");
+       usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, usbatm->flags & UDSL_SKIP_HEAVY_INIT ? "already" : "not");
 
-       if (*need_heavy_init)
-               if ((ret = usb_reset_device(usb_dev)) < 0)
+       if (!(usbatm->flags & UDSL_SKIP_HEAVY_INIT))
+               if ((ret = usb_reset_device(usb_dev)) < 0) {
+                       usb_err(usbatm, "%s: device reset failed (%d)!\n", __func__, ret);
                        goto fail_free;
+               }
 
         usbatm->driver_data = instance;
 
@@ -787,15 +860,15 @@ static void speedtch_unbind(struct usbatm_data *usbatm, struct usb_interface *in
 ***********/
 
 static struct usbatm_driver speedtch_usbatm_driver = {
-       .owner          = THIS_MODULE,
        .driver_name    = speedtch_driver_name,
        .bind           = speedtch_bind,
        .heavy_init     = speedtch_heavy_init,
        .unbind         = speedtch_unbind,
        .atm_start      = speedtch_atm_start,
        .atm_stop       = speedtch_atm_stop,
-       .in             = ENDPOINT_DATA,
-       .out            = ENDPOINT_DATA
+       .bulk_in        = ENDPOINT_BULK_DATA,
+       .bulk_out       = ENDPOINT_BULK_DATA,
+       .isoc_in        = ENDPOINT_ISOC_DATA
 };
 
 static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
index 7d2a679989edf5d8b11a803d15d13dd79b5eb8e7..830d2c982670db964f0263b1958617342c3f7f85 100644 (file)
 #include <linux/ctype.h>
 #include <linux/kthread.h>
 #include <linux/version.h>
+#include <linux/mutex.h>
 #include <asm/unaligned.h>
 
 #include "usbatm.h"
 
-#define EAGLEUSBVERSION "ueagle 1.1"
+#define EAGLEUSBVERSION "ueagle 1.2"
 
 
 /*
@@ -358,16 +359,19 @@ struct intr_pkt {
 #define INTR_PKT_SIZE 28
 
 static struct usb_driver uea_driver;
-static DECLARE_MUTEX(uea_semaphore);
+static DEFINE_MUTEX(uea_mutex);
 static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"};
 
 static int modem_index;
 static unsigned int debug;
+static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};
 static int sync_wait[NB_MODEM];
 static char *cmv_file[NB_MODEM];
 
 module_param(debug, uint, 0644);
 MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");
+module_param_array(use_iso, bool, NULL, 0644);
+MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");
 module_param_array(sync_wait, bool, NULL, 0644);
 MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM");
 module_param_array(cmv_file, charp, NULL, 0644);
@@ -628,8 +632,7 @@ static int request_dsp(struct uea_softc *sc)
                        dsp_name = FW_DIR "DSPep.bin";
        }
 
-       ret = request_firmware(&sc->dsp_firm,
-                               dsp_name, &sc->usb_dev->dev);
+       ret = request_firmware(&sc->dsp_firm, dsp_name, &sc->usb_dev->dev);
        if (ret < 0) {
                uea_err(INS_TO_USBDEV(sc),
                       "requesting firmware %s failed with error %d\n",
@@ -744,7 +747,6 @@ static inline int wait_cmv_ack(struct uea_softc *sc)
                return ret;
 
        return (ret == 0) ? -ETIMEDOUT : 0;
-
 }
 
 #define UCDC_SEND_ENCAPSULATED_COMMAND 0x00
@@ -935,6 +937,7 @@ static int uea_stat(struct uea_softc *sc)
         * ADI930 don't support it (-EPIPE error).
         */
        if (UEA_CHIP_VERSION(sc) != ADI930
+                   && !use_iso[sc->modem_index]
                    && sc->stats.phy.dsrate != (data >> 16) * 32) {
                /* Original timming from ADI(used in windows driver)
                 * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits
@@ -1010,7 +1013,7 @@ static int request_cmvs(struct uea_softc *sc,
        int ret, size;
        u8 *data;
        char *file;
-       static char cmv_name[256] = FW_DIR;
+       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
 
        if (cmv_file[sc->modem_index] == NULL) {
                if (UEA_CHIP_VERSION(sc) == ADI930)
@@ -1184,8 +1187,7 @@ static int load_XILINX_firmware(struct uea_softc *sc)
                }
        }
 
-       /* finish to send the fpga
-        */
+       /* finish to send the fpga */
        ret = uea_request(sc, 0xe, 1, 0, NULL);
        if (ret < 0) {
                uea_err(INS_TO_USBDEV(sc),
@@ -1193,9 +1195,7 @@ static int load_XILINX_firmware(struct uea_softc *sc)
                goto err1;
        }
 
-       /*
-        * Tell the modem we finish : de-assert reset
-        */
+       /* Tell the modem we finish : de-assert reset */
        value = 0;
        ret = uea_send_modem_cmd(sc->usb_dev, 0xe, 1, &value);
        if (ret < 0)
@@ -1209,6 +1209,7 @@ err0:
        return ret;
 }
 
+/* The modem send us an ack. First with check if it right */
 static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
 {
        uea_enters(INS_TO_USBDEV(sc));
@@ -1268,23 +1269,19 @@ bad1:
  */
 static void uea_intr(struct urb *urb, struct pt_regs *regs)
 {
-       struct uea_softc *sc = (struct uea_softc *)urb->context;
-       struct intr_pkt *intr;
+       struct uea_softc *sc = urb->context;
+       struct intr_pkt *intr = urb->transfer_buffer;
        uea_enters(INS_TO_USBDEV(sc));
 
-       if (urb->status < 0) {
+       if (unlikely(urb->status < 0)) {
                uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n",
                       urb->status);
                return;
        }
 
-       intr = (struct intr_pkt *) urb->transfer_buffer;
-
        /* device-to-host interrupt */
        if (intr->bType != 0x08 || sc->booting) {
-               uea_err(INS_TO_USBDEV(sc), "wrong intr\n");
-               // rebooting ?
-               // sc->reset = 1;
+               uea_err(INS_TO_USBDEV(sc), "wrong interrupt\n");
                goto resubmit;
        }
 
@@ -1300,7 +1297,7 @@ static void uea_intr(struct urb *urb, struct pt_regs *regs)
                break;
 
        default:
-               uea_err(INS_TO_USBDEV(sc), "unknown intr %u\n",
+               uea_err(INS_TO_USBDEV(sc), "unknown interrupt %u\n",
                       le16_to_cpu(intr->wInterrupt));
        }
 
@@ -1379,7 +1376,7 @@ static void uea_stop(struct uea_softc *sc)
        int ret;
        uea_enters(INS_TO_USBDEV(sc));
        ret = kthread_stop(sc->kthread);
-       uea_info(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
+       uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
 
        /* stop any pending boot process */
        flush_scheduled_work();
@@ -1418,13 +1415,13 @@ static ssize_t read_status(struct device *dev, struct device_attribute *attr,
        int ret = -ENODEV;
        struct uea_softc *sc;
 
-       down(&uea_semaphore);
+       mutex_lock(&uea_mutex);
        sc = dev_to_uea(dev);
        if (!sc)
                goto out;
        ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.state);
 out:
-       up(&uea_semaphore);
+       mutex_unlock(&uea_mutex);
        return ret;
 }
 
@@ -1434,14 +1431,14 @@ static ssize_t reboot(struct device *dev, struct device_attribute *attr,
        int ret = -ENODEV;
        struct uea_softc *sc;
 
-       down(&uea_semaphore);
+       mutex_lock(&uea_mutex);
        sc = dev_to_uea(dev);
        if (!sc)
                goto out;
        sc->reset = 1;
        ret = count;
 out:
-       up(&uea_semaphore);
+       mutex_unlock(&uea_mutex);
        return ret;
 }
 
@@ -1453,7 +1450,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
        int ret = -ENODEV;
        struct uea_softc *sc;
 
-       down(&uea_semaphore);
+       mutex_lock(&uea_mutex);
        sc = dev_to_uea(dev);
        if (!sc)
                goto out;
@@ -1473,7 +1470,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
                break;
        }
 out:
-       up(&uea_semaphore);
+       mutex_unlock(&uea_mutex);
        return ret;
 }
 
@@ -1485,7 +1482,7 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
        int ret = -ENODEV;
        struct uea_softc *sc;
 
-       down(&uea_semaphore);
+       mutex_lock(&uea_mutex);
        sc = dev_to_uea(dev);
        if (!sc)
                goto out;
@@ -1497,7 +1494,7 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
        else
                ret = sprintf(buf, "GOOD\n");
 out:
-       up(&uea_semaphore);
+       mutex_unlock(&uea_mutex);
        return ret;
 }
 
@@ -1511,7 +1508,7 @@ static ssize_t read_##name(struct device *dev,                    \
        int ret = -ENODEV;                                      \
        struct uea_softc *sc;                                   \
                                                                \
-       down(&uea_semaphore);                                   \
+       mutex_lock(&uea_mutex);                                         \
        sc = dev_to_uea(dev);                                   \
        if (!sc)                                                \
                goto out;                                       \
@@ -1519,7 +1516,7 @@ static ssize_t read_##name(struct device *dev,                    \
        if (reset)                                              \
                sc->stats.phy.name = 0;                         \
 out:                                                           \
-       up(&uea_semaphore);                                     \
+       mutex_unlock(&uea_mutex);                                       \
        return ret;                                             \
 }                                                              \
                                                                \
@@ -1617,7 +1614,7 @@ static void create_fs_entries(struct uea_softc *sc, struct usb_interface *intf)
 }
 
 static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
-                  const struct usb_device_id *id, int *heavy)
+                  const struct usb_device_id *id)
 {
        struct usb_device *usb = interface_to_usbdev(intf);
        struct uea_softc *sc;
@@ -1629,16 +1626,14 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
        if (ifnum != UEA_INTR_IFACE_NO)
                return -ENODEV;
 
-       *heavy = sync_wait[modem_index];
+       usbatm->flags = (sync_wait[modem_index] ? 0 : UDSL_SKIP_HEAVY_INIT);
 
        /* interface 1 is for outbound traffic */
        ret = claim_interface(usb, usbatm, UEA_US_IFACE_NO);
        if (ret < 0)
                return ret;
 
-       /* ADI930 has only 2 interfaces and inbound traffic
-        * is on interface 1
-        */
+       /* ADI930 has only 2 interfaces and inbound traffic is on interface 1 */
        if (UEA_CHIP_VERSION(id) != ADI930) {
                /* interface 2 is for inbound traffic */
                ret = claim_interface(usb, usbatm, UEA_DS_IFACE_NO);
@@ -1658,6 +1653,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
        sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0;
        sc->driver_info = id->driver_info;
 
+       /* ADI930 don't support iso */
+       if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) {
+               int i;
+
+               /* try set fastest alternate for inbound traffic interface */
+               for (i = FASTEST_ISO_INTF; i > 0; i--)
+                       if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0)
+                               break;
+
+               if (i > 0) {
+                       uea_dbg(usb, "set alternate %d for 2 interface\n", i);
+                       uea_info(usb, "using iso mode\n");
+                       usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
+               } else {
+                       uea_err(usb, "setting any alternate failed for "
+                                       "2 interface, using bulk mode\n");
+               }
+       }
+
        ret = uea_boot(sc);
        if (ret < 0) {
                kfree(sc);
@@ -1701,13 +1715,13 @@ static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
 
 static struct usbatm_driver uea_usbatm_driver = {
        .driver_name = "ueagle-atm",
-       .owner = THIS_MODULE,
        .bind = uea_bind,
        .atm_start = uea_atm_open,
        .unbind = uea_unbind,
        .heavy_init = uea_heavy,
-       .in = UEA_BULK_DATA_PIPE,
-       .out = UEA_BULK_DATA_PIPE,
+       .bulk_in = UEA_BULK_DATA_PIPE,
+       .bulk_out = UEA_BULK_DATA_PIPE,
+       .isoc_in = UEA_ISO_DATA_PIPE,
 };
 
 static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -1738,9 +1752,9 @@ static void uea_disconnect(struct usb_interface *intf)
         * Pre-firmware device has one interface
         */
        if (usb->config->desc.bNumInterfaces != 1 && ifnum == 0) {
-               down(&uea_semaphore);
+               mutex_lock(&uea_mutex);
                usbatm_usb_disconnect(intf);
-               up(&uea_semaphore);
+               mutex_unlock(&uea_mutex);
                uea_info(usb, "ADSL device removed\n");
        }
 
index 7af1883d4bf9cf127c183089ef52c8fbd5f2703d..c1211fc037d997b8a30cee323ded090d72d9da63 100644 (file)
@@ -72,6 +72,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
@@ -91,19 +92,18 @@ static int usbatm_print_packet(const unsigned char *data, int len);
 #endif
 
 #define DRIVER_AUTHOR  "Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
-#define DRIVER_VERSION "1.9"
+#define DRIVER_VERSION "1.10"
 #define DRIVER_DESC    "Generic USB ATM/DSL I/O, version " DRIVER_VERSION
 
 static const char usbatm_driver_name[] = "usbatm";
 
 #define UDSL_MAX_RCV_URBS              16
 #define UDSL_MAX_SND_URBS              16
-#define UDSL_MAX_RCV_BUF_SIZE          1024    /* ATM cells */
-#define UDSL_MAX_SND_BUF_SIZE          1024    /* ATM cells */
+#define UDSL_MAX_BUF_SIZE              64 * 1024       /* bytes */
 #define UDSL_DEFAULT_RCV_URBS          4
 #define UDSL_DEFAULT_SND_URBS          4
-#define UDSL_DEFAULT_RCV_BUF_SIZE      64      /* ATM cells */
-#define UDSL_DEFAULT_SND_BUF_SIZE      64      /* ATM cells */
+#define UDSL_DEFAULT_RCV_BUF_SIZE      64 * ATM_CELL_SIZE      /* bytes */
+#define UDSL_DEFAULT_SND_BUF_SIZE      64 * ATM_CELL_SIZE      /* bytes */
 
 #define ATM_CELL_HEADER                        (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
 
@@ -111,8 +111,8 @@ static const char usbatm_driver_name[] = "usbatm";
 
 static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS;
 static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS;
-static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE;
-static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE;
+static unsigned int rcv_buf_bytes = UDSL_DEFAULT_RCV_BUF_SIZE;
+static unsigned int snd_buf_bytes = UDSL_DEFAULT_SND_BUF_SIZE;
 
 module_param(num_rcv_urbs, uint, S_IRUGO);
 MODULE_PARM_DESC(num_rcv_urbs,
@@ -126,15 +126,15 @@ MODULE_PARM_DESC(num_snd_urbs,
                 __MODULE_STRING(UDSL_MAX_SND_URBS) ", default: "
                 __MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")");
 
-module_param(rcv_buf_size, uint, S_IRUGO);
-MODULE_PARM_DESC(rcv_buf_size,
-                "Size of the buffers used for reception in ATM cells (range: 1-"
-                __MODULE_STRING(UDSL_MAX_RCV_BUF_SIZE) ", default: "
+module_param(rcv_buf_bytes, uint, S_IRUGO);
+MODULE_PARM_DESC(rcv_buf_bytes,
+                "Size of the buffers used for reception, in bytes (range: 1-"
+                __MODULE_STRING(UDSL_MAX_BUF_SIZE) ", default: "
                 __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")");
 
-module_param(snd_buf_size, uint, S_IRUGO);
-MODULE_PARM_DESC(snd_buf_size,
-                "Size of the buffers used for transmission in ATM cells (range: 1-"
+module_param(snd_buf_bytes, uint, S_IRUGO);
+MODULE_PARM_DESC(snd_buf_bytes,
+                "Size of the buffers used for transmission, in bytes (range: 1-"
                 __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: "
                 __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")");
 
@@ -166,10 +166,10 @@ struct usbatm_control {
 
 /* ATM */
 
-static void usbatm_atm_dev_close(struct atm_dev *dev);
+static void usbatm_atm_dev_close(struct atm_dev *atm_dev);
 static int usbatm_atm_open(struct atm_vcc *vcc);
 static void usbatm_atm_close(struct atm_vcc *vcc);
-static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg);
+static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user * arg);
 static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb);
 static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page);
 
@@ -199,7 +199,7 @@ static inline void usbatm_pop(struct atm_vcc *vcc, struct sk_buff *skb)
        if (vcc->pop)
                vcc->pop(vcc, skb);
        else
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
 }
 
 
@@ -234,8 +234,9 @@ static int usbatm_submit_urb(struct urb *urb)
 
        ret = usb_submit_urb(urb, GFP_ATOMIC);
        if (ret) {
-               atm_dbg(channel->usbatm, "%s: urb 0x%p submission failed (%d)!\n",
-                       __func__, urb, ret);
+               if (printk_ratelimit())
+                       atm_warn(channel->usbatm, "%s: urb 0x%p submission failed (%d)!\n",
+                               __func__, urb, ret);
 
                /* consider all errors transient and return the buffer back to the queue */
                urb->status = -EAGAIN;
@@ -269,10 +270,16 @@ static void usbatm_complete(struct urb *urb, struct pt_regs *regs)
 
        spin_unlock_irqrestore(&channel->lock, flags);
 
-       if (unlikely(urb->status))
+       if (unlikely(urb->status) &&
+                       (!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
+                        urb->status != -EILSEQ ))
+       {
+               if (printk_ratelimit())
+                       atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n",
+                               __func__, urb, urb->status);
                /* throttle processing in case of an error */
                mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
-       else
+       else
                tasklet_schedule(&channel->tasklet);
 }
 
@@ -284,129 +291,167 @@ static void usbatm_complete(struct urb *urb, struct pt_regs *regs)
 static inline struct usbatm_vcc_data *usbatm_find_vcc(struct usbatm_data *instance,
                                                  short vpi, int vci)
 {
-       struct usbatm_vcc_data *vcc;
+       struct usbatm_vcc_data *vcc_data;
 
-       list_for_each_entry(vcc, &instance->vcc_list, list)
-               if ((vcc->vci == vci) && (vcc->vpi == vpi))
-                       return vcc;
+       list_for_each_entry(vcc_data, &instance->vcc_list, list)
+               if ((vcc_data->vci == vci) && (vcc_data->vpi == vpi))
+                       return vcc_data;
        return NULL;
 }
 
-static void usbatm_extract_cells(struct usbatm_data *instance,
-                              unsigned char *source, unsigned int avail_data)
+static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char *source)
 {
-       struct usbatm_vcc_data *cached_vcc = NULL;
        struct atm_vcc *vcc;
        struct sk_buff *sarb;
-       unsigned int stride = instance->rx_channel.stride;
-       int vci, cached_vci = 0;
-       short vpi, cached_vpi = 0;
-       u8 pti;
+       short vpi = ((source[0] & 0x0f) << 4)  | (source[1] >> 4);
+       int vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
+       u8 pti = ((source[3] & 0xe) >> 1);
 
-       for (; avail_data >= stride; avail_data -= stride, source += stride) {
-               vpi = ((source[0] & 0x0f) << 4)  | (source[1] >> 4);
-               vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
-               pti = ((source[3] & 0xe) >> 1);
+       vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
 
-               vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
+       if ((vci != instance->cached_vci) || (vpi != instance->cached_vpi)) {
+               instance->cached_vpi = vpi;
+               instance->cached_vci = vci;
 
-               if ((vci != cached_vci) || (vpi != cached_vpi)) {
-                       cached_vpi = vpi;
-                       cached_vci = vci;
+               instance->cached_vcc = usbatm_find_vcc(instance, vpi, vci);
 
-                       cached_vcc = usbatm_find_vcc(instance, vpi, vci);
+               if (!instance->cached_vcc)
+                       atm_rldbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci);
+       }
 
-                       if (!cached_vcc)
-                               atm_dbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci);
-               }
+       if (!instance->cached_vcc)
+               return;
 
-               if (!cached_vcc)
-                       continue;
+       vcc = instance->cached_vcc->vcc;
 
-               vcc = cached_vcc->vcc;
+       /* OAM F5 end-to-end */
+       if (pti == ATM_PTI_E2EF5) {
+               if (printk_ratelimit())
+                       atm_warn(instance, "%s: OAM not supported (vpi %d, vci %d)!\n",
+                               __func__, vpi, vci);
+               atomic_inc(&vcc->stats->rx_err);
+               return;
+       }
 
-               /* OAM F5 end-to-end */
-               if (pti == ATM_PTI_E2EF5) {
-                       atm_warn(instance, "%s: OAM not supported (vpi %d, vci %d)!\n", __func__, vpi, vci);
-                       atomic_inc(&vcc->stats->rx_err);
-                       continue;
-               }
+       sarb = instance->cached_vcc->sarb;
 
-               sarb = cached_vcc->sarb;
+       if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
+               atm_rldbg(instance, "%s: buffer overrun (sarb->len %u, vcc: 0x%p)!\n",
+                               __func__, sarb->len, vcc);
+               /* discard cells already received */
+               skb_trim(sarb, 0);
+               UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
+       }
 
-               if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
-                       atm_dbg(instance, "%s: buffer overrun (sarb->len %u, vcc: 0x%p)!\n",
-                                       __func__, sarb->len, vcc);
-                       /* discard cells already received */
-                       skb_trim(sarb, 0);
-                       UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
-               }
+       memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
+       __skb_put(sarb, ATM_CELL_PAYLOAD);
 
-               memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
-               __skb_put(sarb, ATM_CELL_PAYLOAD);
+       if (pti & 1) {
+               struct sk_buff *skb;
+               unsigned int length;
+               unsigned int pdu_length;
 
-               if (pti & 1) {
-                       struct sk_buff *skb;
-                       unsigned int length;
-                       unsigned int pdu_length;
+               length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5];
 
-                       length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5];
+               /* guard against overflow */
+               if (length > ATM_MAX_AAL5_PDU) {
+                       atm_rldbg(instance, "%s: bogus length %u (vcc: 0x%p)!\n",
+                                 __func__, length, vcc);
+                       atomic_inc(&vcc->stats->rx_err);
+                       goto out;
+               }
 
-                       /* guard against overflow */
-                       if (length > ATM_MAX_AAL5_PDU) {
-                               atm_dbg(instance, "%s: bogus length %u (vcc: 0x%p)!\n",
-                                               __func__, length, vcc);
-                               atomic_inc(&vcc->stats->rx_err);
-                               goto out;
-                       }
+               pdu_length = usbatm_pdu_length(length);
 
-                       pdu_length = usbatm_pdu_length(length);
+               if (sarb->len < pdu_length) {
+                       atm_rldbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n",
+                                 __func__, pdu_length, sarb->len, vcc);
+                       atomic_inc(&vcc->stats->rx_err);
+                       goto out;
+               }
 
-                       if (sarb->len < pdu_length) {
-                               atm_dbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n",
-                                               __func__, pdu_length, sarb->len, vcc);
-                               atomic_inc(&vcc->stats->rx_err);
-                               goto out;
-                       }
+               if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
+                       atm_rldbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n",
+                                 __func__, vcc);
+                       atomic_inc(&vcc->stats->rx_err);
+                       goto out;
+               }
 
-                       if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
-                               atm_dbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n",
-                                               __func__, vcc);
-                               atomic_inc(&vcc->stats->rx_err);
-                               goto out;
-                       }
+               vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc);
 
-                       vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc);
+               if (!(skb = dev_alloc_skb(length))) {
+                       if (printk_ratelimit())
+                               atm_err(instance, "%s: no memory for skb (length: %u)!\n",
+                                       __func__, length);
+                       atomic_inc(&vcc->stats->rx_drop);
+                       goto out;
+               }
 
-                       if (!(skb = dev_alloc_skb(length))) {
-                               atm_dbg(instance, "%s: no memory for skb (length: %u)!\n", __func__, length);
-                               atomic_inc(&vcc->stats->rx_drop);
-                               goto out;
-                       }
+               vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize);
 
-                       vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize);
+               if (!atm_charge(vcc, skb->truesize)) {
+                       atm_rldbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n",
+                                 __func__, skb->truesize);
+                       dev_kfree_skb_any(skb);
+                       goto out;       /* atm_charge increments rx_drop */
+               }
 
-                       if (!atm_charge(vcc, skb->truesize)) {
-                               atm_dbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n", __func__, skb->truesize);
-                               dev_kfree_skb(skb);
-                               goto out;       /* atm_charge increments rx_drop */
-                       }
+               memcpy(skb->data, sarb->tail - pdu_length, length);
+               __skb_put(skb, length);
 
-                       memcpy(skb->data, sarb->tail - pdu_length, length);
-                       __skb_put(skb, length);
+               vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u",
+                    __func__, skb, skb->len, skb->truesize);
 
-                       vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u",
-                            __func__, skb, skb->len, skb->truesize);
+               PACKETDEBUG(skb->data, skb->len);
 
-                       PACKETDEBUG(skb->data, skb->len);
+               vcc->push(vcc, skb);
 
-                       vcc->push(vcc, skb);
+               atomic_inc(&vcc->stats->rx);
+       out:
+               skb_trim(sarb, 0);
+       }
+}
 
-                       atomic_inc(&vcc->stats->rx);
-               out:
-                       skb_trim(sarb, 0);
+static void usbatm_extract_cells(struct usbatm_data *instance,
+               unsigned char *source, unsigned int avail_data)
+{
+       unsigned int stride = instance->rx_channel.stride;
+       unsigned int buf_usage = instance->buf_usage;
+
+       /* extract cells from incoming data, taking into account that
+        * the length of avail data may not be a multiple of stride */
+
+       if (buf_usage > 0) {
+               /* we have a partially received atm cell */
+               unsigned char *cell_buf = instance->cell_buf;
+               unsigned int space_left = stride - buf_usage;
+
+               UDSL_ASSERT(buf_usage <= stride);
+
+               if (avail_data >= space_left) {
+                       /* add new data and process cell */
+                       memcpy(cell_buf + buf_usage, source, space_left);
+                       source += space_left;
+                       avail_data -= space_left;
+                       usbatm_extract_one_cell(instance, cell_buf);
+                       instance->buf_usage = 0;
+               } else {
+                       /* not enough data to fill the cell */
+                       memcpy(cell_buf + buf_usage, source, avail_data);
+                       instance->buf_usage = buf_usage + avail_data;
+                       return;
                }
        }
+
+       for (; avail_data >= stride; avail_data -= stride, source += stride)
+               usbatm_extract_one_cell(instance, source);
+
+       if (avail_data > 0) {
+               /* length was not a multiple of stride -
+                * save remaining data for next call */
+               memcpy(instance->cell_buf, source, avail_data);
+               instance->buf_usage = avail_data;
+       }
 }
 
 
@@ -420,14 +465,14 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance,
 {
        struct usbatm_control *ctrl = UDSL_SKB(skb);
        struct atm_vcc *vcc = ctrl->atm.vcc;
-       unsigned int num_written;
+       unsigned int bytes_written;
        unsigned int stride = instance->tx_channel.stride;
 
        vdbg("%s: skb->len=%d, avail_space=%u", __func__, skb->len, avail_space);
        UDSL_ASSERT(!(avail_space % stride));
 
-       for (num_written = 0; num_written < avail_space && ctrl->len;
-            num_written += stride, target += stride) {
+       for (bytes_written = 0; bytes_written < avail_space && ctrl->len;
+            bytes_written += stride, target += stride) {
                unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD);
                unsigned int left = ATM_CELL_PAYLOAD - data_len;
                u8 *ptr = target;
@@ -470,7 +515,7 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance,
                        ctrl->crc = crc32_be(ctrl->crc, ptr, left);
        }
 
-       return num_written;
+       return bytes_written;
 }
 
 
@@ -487,16 +532,40 @@ static void usbatm_rx_process(unsigned long data)
                vdbg("%s: processing urb 0x%p", __func__, urb);
 
                if (usb_pipeisoc(urb->pipe)) {
+                       unsigned char *merge_start = NULL;
+                       unsigned int merge_length = 0;
+                       const unsigned int packet_size = instance->rx_channel.packet_size;
                        int i;
-                       for (i = 0; i < urb->number_of_packets; i++)
-                               if (!urb->iso_frame_desc[i].status)
-                                       usbatm_extract_cells(instance,
-                                                            (u8 *)urb->transfer_buffer + urb->iso_frame_desc[i].offset,
-                                                            urb->iso_frame_desc[i].actual_length);
-               }
-               else
+
+                       for (i = 0; i < urb->number_of_packets; i++) {
+                               if (!urb->iso_frame_desc[i].status) {
+                                       unsigned int actual_length = urb->iso_frame_desc[i].actual_length;
+
+                                       UDSL_ASSERT(actual_length <= packet_size);
+
+                                       if (!merge_length)
+                                               merge_start = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+                                       merge_length += actual_length;
+                                       if (merge_length && (actual_length < packet_size)) {
+                                               usbatm_extract_cells(instance, merge_start, merge_length);
+                                               merge_length = 0;
+                                       }
+                               } else {
+                                       atm_rldbg(instance, "%s: status %d in frame %d!\n", __func__, urb->status, i);
+                                       if (merge_length)
+                                               usbatm_extract_cells(instance, merge_start, merge_length);
+                                       merge_length = 0;
+                                       instance->buf_usage = 0;
+                               }
+                       }
+
+                       if (merge_length)
+                               usbatm_extract_cells(instance, merge_start, merge_length);
+               } else
                        if (!urb->status)
                                usbatm_extract_cells(instance, urb->transfer_buffer, urb->actual_length);
+                       else
+                               instance->buf_usage = 0;
 
                if (usbatm_submit_urb(urb))
                        return;
@@ -514,7 +583,7 @@ static void usbatm_tx_process(unsigned long data)
        struct sk_buff *skb = instance->current_skb;
        struct urb *urb = NULL;
        const unsigned int buf_size = instance->tx_channel.buf_size;
-       unsigned int num_written = 0;
+       unsigned int bytes_written = 0;
        u8 *buffer = NULL;
 
        if (!skb)
@@ -526,16 +595,16 @@ static void usbatm_tx_process(unsigned long data)
                        if (!urb)
                                break;          /* no more senders */
                        buffer = urb->transfer_buffer;
-                       num_written = (urb->status == -EAGAIN) ?
+                       bytes_written = (urb->status == -EAGAIN) ?
                                urb->transfer_buffer_length : 0;
                }
 
-               num_written += usbatm_write_cells(instance, skb,
-                                                 buffer + num_written,
-                                                 buf_size - num_written);
+               bytes_written += usbatm_write_cells(instance, skb,
+                                                 buffer + bytes_written,
+                                                 buf_size - bytes_written);
 
                vdbg("%s: wrote %u bytes from skb 0x%p to urb 0x%p",
-                    __func__, num_written, skb, urb);
+                    __func__, bytes_written, skb, urb);
 
                if (!UDSL_SKB(skb)->len) {
                        struct atm_vcc *vcc = UDSL_SKB(skb)->atm.vcc;
@@ -546,8 +615,8 @@ static void usbatm_tx_process(unsigned long data)
                        skb = skb_dequeue(&instance->sndqueue);
                }
 
-               if (num_written == buf_size || (!skb && num_written)) {
-                       urb->transfer_buffer_length = num_written;
+               if (bytes_written == buf_size || (!skb && bytes_written)) {
+                       urb->transfer_buffer_length = bytes_written;
 
                        if (usbatm_submit_urb(urb))
                                break;
@@ -593,20 +662,24 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
 
        vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len);
 
-       if (!instance) {
-               dbg("%s: NULL data!", __func__);
+       /* racy disconnection check - fine */
+       if (!instance || instance->disconnected) {
+#ifdef DEBUG
+               if (printk_ratelimit())
+                       printk(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
+#endif
                err = -ENODEV;
                goto fail;
        }
 
        if (vcc->qos.aal != ATM_AAL5) {
-               atm_dbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
+               atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
                err = -EINVAL;
                goto fail;
        }
 
        if (skb->len > ATM_MAX_AAL5_PDU) {
-               atm_dbg(instance, "%s: packet too long (%d vs %d)!\n",
+               atm_rldbg(instance, "%s: packet too long (%d vs %d)!\n",
                                __func__, skb->len, ATM_MAX_AAL5_PDU);
                err = -EINVAL;
                goto fail;
@@ -665,16 +738,16 @@ static void usbatm_put_instance(struct usbatm_data *instance)
 **  ATM  **
 **********/
 
-static void usbatm_atm_dev_close(struct atm_dev *dev)
+static void usbatm_atm_dev_close(struct atm_dev *atm_dev)
 {
-       struct usbatm_data *instance = dev->dev_data;
+       struct usbatm_data *instance = atm_dev->dev_data;
 
        dbg("%s", __func__);
 
        if (!instance)
                return;
 
-       dev->dev_data = NULL;
+       atm_dev->dev_data = NULL; /* catch bugs */
        usbatm_put_instance(instance);  /* taken in usbatm_atm_init */
 }
 
@@ -706,15 +779,19 @@ static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *pag
                               atomic_read(&atm_dev->stats.aal5.rx_err),
                               atomic_read(&atm_dev->stats.aal5.rx_drop));
 
-       if (!left--)
-               switch (atm_dev->signal) {
-               case ATM_PHY_SIG_FOUND:
-                       return sprintf(page, "Line up\n");
-               case ATM_PHY_SIG_LOST:
-                       return sprintf(page, "Line down\n");
-               default:
-                       return sprintf(page, "Line state unknown\n");
-               }
+       if (!left--) {
+               if (instance->disconnected)
+                       return sprintf(page, "Disconnected\n");
+               else
+                       switch (atm_dev->signal) {
+                       case ATM_PHY_SIG_FOUND:
+                               return sprintf(page, "Line up\n");
+                       case ATM_PHY_SIG_LOST:
+                               return sprintf(page, "Line down\n");
+                       default:
+                               return sprintf(page, "Line state unknown\n");
+                       }
+       }
 
        return 0;
 }
@@ -735,13 +812,24 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
        atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);
 
        /* only support AAL5 */
-       if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0)
-           || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) {
-               atm_dbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
+       if ((vcc->qos.aal != ATM_AAL5)) {
+               atm_warn(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
+               return -EINVAL;
+       }
+
+       /* sanity checks */
+       if ((vcc->qos.rxtp.max_sdu < 0) || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) {
+               atm_dbg(instance, "%s: max_sdu %d out of range!\n", __func__, vcc->qos.rxtp.max_sdu);
                return -EINVAL;
        }
 
-       down(&instance->serialize);     /* vs self, usbatm_atm_close */
+       mutex_lock(&instance->serialize);       /* vs self, usbatm_atm_close, usbatm_usb_disconnect */
+
+       if (instance->disconnected) {
+               atm_dbg(instance, "%s: disconnected!\n", __func__);
+               ret = -ENODEV;
+               goto fail;
+       }
 
        if (usbatm_find_vcc(instance, vpi, vci)) {
                atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci);
@@ -749,20 +837,19 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
                goto fail;
        }
 
-       if (!(new = kmalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL))) {
-               atm_dbg(instance, "%s: no memory for vcc_data!\n", __func__);
+       if (!(new = kzalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL))) {
+               atm_err(instance, "%s: no memory for vcc_data!\n", __func__);
                ret = -ENOMEM;
                goto fail;
        }
 
-       memset(new, 0, sizeof(struct usbatm_vcc_data));
        new->vcc = vcc;
        new->vpi = vpi;
        new->vci = vci;
 
        new->sarb = alloc_skb(usbatm_pdu_length(vcc->qos.rxtp.max_sdu), GFP_KERNEL);
        if (!new->sarb) {
-               atm_dbg(instance, "%s: no memory for SAR buffer!\n", __func__);
+               atm_err(instance, "%s: no memory for SAR buffer!\n", __func__);
                ret = -ENOMEM;
                goto fail;
        }
@@ -770,6 +857,9 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
        vcc->dev_data = new;
 
        tasklet_disable(&instance->rx_channel.tasklet);
+       instance->cached_vcc = new;
+       instance->cached_vpi = vpi;
+       instance->cached_vci = vci;
        list_add(&new->list, &instance->vcc_list);
        tasklet_enable(&instance->rx_channel.tasklet);
 
@@ -777,7 +867,7 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
        set_bit(ATM_VF_PARTIAL, &vcc->flags);
        set_bit(ATM_VF_READY, &vcc->flags);
 
-       up(&instance->serialize);
+       mutex_unlock(&instance->serialize);
 
        atm_dbg(instance, "%s: allocated vcc data 0x%p\n", __func__, new);
 
@@ -785,7 +875,7 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
 
 fail:
        kfree(new);
-       up(&instance->serialize);
+       mutex_unlock(&instance->serialize);
        return ret;
 }
 
@@ -806,9 +896,14 @@ static void usbatm_atm_close(struct atm_vcc *vcc)
 
        usbatm_cancel_send(instance, vcc);
 
-       down(&instance->serialize);     /* vs self, usbatm_atm_open */
+       mutex_lock(&instance->serialize);       /* vs self, usbatm_atm_open, usbatm_usb_disconnect */
 
        tasklet_disable(&instance->rx_channel.tasklet);
+       if (instance->cached_vcc == vcc_data) {
+               instance->cached_vcc = NULL;
+               instance->cached_vpi = ATM_VPI_UNSPEC;
+               instance->cached_vci = ATM_VCI_UNSPEC;
+       }
        list_del(&vcc_data->list);
        tasklet_enable(&instance->rx_channel.tasklet);
 
@@ -824,14 +919,21 @@ static void usbatm_atm_close(struct atm_vcc *vcc)
        clear_bit(ATM_VF_PARTIAL, &vcc->flags);
        clear_bit(ATM_VF_ADDR, &vcc->flags);
 
-       up(&instance->serialize);
+       mutex_unlock(&instance->serialize);
 
        atm_dbg(instance, "%s successful\n", __func__);
 }
 
-static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd,
+static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd,
                          void __user * arg)
 {
+       struct usbatm_data *instance = atm_dev->dev_data;
+
+       if (!instance || instance->disconnected) {
+               dbg("%s: %s!", __func__, instance ? "disconnected" : "NULL instance");
+               return -ENODEV;
+       }
+
        switch (cmd) {
        case ATM_QUERYLOOP:
                return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0;
@@ -845,10 +947,13 @@ static int usbatm_atm_init(struct usbatm_data *instance)
        struct atm_dev *atm_dev;
        int ret, i;
 
-       /* ATM init */
+       /* ATM init.  The ATM initialization scheme suffers from an intrinsic race
+        * condition: callbacks we register can be executed at once, before we have
+        * initialized the struct atm_dev.  To protect against this, all callbacks
+        * abort if atm_dev->dev_data is NULL. */
        atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL);
        if (!atm_dev) {
-               usb_dbg(instance, "%s: failed to register ATM device!\n", __func__);
+               usb_err(instance, "%s: failed to register ATM device!\n", __func__);
                return -1;
        }
 
@@ -862,12 +967,13 @@ static int usbatm_atm_init(struct usbatm_data *instance)
        atm_dev->link_rate = 128 * 1000 / 424;
 
        if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) {
-               atm_dbg(instance, "%s: atm_start failed: %d!\n", __func__, ret);
+               atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret);
                goto fail;
        }
 
-       /* ready for ATM callbacks */
        usbatm_get_instance(instance);  /* dropped in usbatm_atm_dev_close */
+
+       /* ready for ATM callbacks */
        mb();
        atm_dev->dev_data = instance;
 
@@ -903,9 +1009,9 @@ static int usbatm_do_heavy_init(void *arg)
        if (!ret)
                ret = usbatm_atm_init(instance);
 
-       down(&instance->serialize);
+       mutex_lock(&instance->serialize);
        instance->thread_pid = -1;
-       up(&instance->serialize);
+       mutex_unlock(&instance->serialize);
 
        complete_and_exit(&instance->thread_exited, ret);
 }
@@ -915,13 +1021,13 @@ static int usbatm_heavy_init(struct usbatm_data *instance)
        int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL);
 
        if (ret < 0) {
-               usb_dbg(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
+               usb_err(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
                return ret;
        }
 
-       down(&instance->serialize);
+       mutex_lock(&instance->serialize);
        instance->thread_pid = ret;
-       up(&instance->serialize);
+       mutex_unlock(&instance->serialize);
 
        wait_for_completion(&instance->thread_started);
 
@@ -951,9 +1057,9 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
        char *buf;
        int error = -ENOMEM;
        int i, length;
-       int need_heavy;
+       unsigned int maxpacket, num_packets;
 
-       dev_dbg(dev, "%s: trying driver %s with vendor=0x%x, product=0x%x, ifnum %d\n",
+       dev_dbg(dev, "%s: trying driver %s with vendor=%04x, product=%04x, ifnum %2d\n",
                        __func__, driver->driver_name,
                        le16_to_cpu(usb_dev->descriptor.idVendor),
                        le16_to_cpu(usb_dev->descriptor.idProduct),
@@ -962,7 +1068,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
        /* instance init */
        instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
        if (!instance) {
-               dev_dbg(dev, "%s: no memory for instance data!\n", __func__);
+               dev_err(dev, "%s: no memory for instance data!\n", __func__);
                return -ENOMEM;
        }
 
@@ -996,66 +1102,96 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
        snprintf(buf, length, ")");
 
  bind:
-       need_heavy = 1;
-       if (driver->bind && (error = driver->bind(instance, intf, id, &need_heavy)) < 0) {
-                       dev_dbg(dev, "%s: bind failed: %d!\n", __func__, error);
+       if (driver->bind && (error = driver->bind(instance, intf, id)) < 0) {
+                       dev_err(dev, "%s: bind failed: %d!\n", __func__, error);
                        goto fail_free;
        }
 
        /* private fields */
 
        kref_init(&instance->refcount);         /* dropped in usbatm_usb_disconnect */
-       init_MUTEX(&instance->serialize);
+       mutex_init(&instance->serialize);
 
        instance->thread_pid = -1;
        init_completion(&instance->thread_started);
        init_completion(&instance->thread_exited);
 
        INIT_LIST_HEAD(&instance->vcc_list);
+       skb_queue_head_init(&instance->sndqueue);
 
        usbatm_init_channel(&instance->rx_channel);
        usbatm_init_channel(&instance->tx_channel);
        tasklet_init(&instance->rx_channel.tasklet, usbatm_rx_process, (unsigned long)instance);
        tasklet_init(&instance->tx_channel.tasklet, usbatm_tx_process, (unsigned long)instance);
-       instance->rx_channel.endpoint = usb_rcvbulkpipe(usb_dev, driver->in);
-       instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->out);
        instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding;
        instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding;
-       instance->rx_channel.buf_size = rcv_buf_size * instance->rx_channel.stride;
-       instance->tx_channel.buf_size = snd_buf_size * instance->tx_channel.stride;
        instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance;
 
-       skb_queue_head_init(&instance->sndqueue);
+       if ((instance->flags & UDSL_USE_ISOC) && driver->isoc_in)
+               instance->rx_channel.endpoint = usb_rcvisocpipe(usb_dev, driver->isoc_in);
+       else
+               instance->rx_channel.endpoint = usb_rcvbulkpipe(usb_dev, driver->bulk_in);
+
+       instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->bulk_out);
+
+       /* tx buffer size must be a positive multiple of the stride */
+       instance->tx_channel.buf_size = max (instance->tx_channel.stride,
+                       snd_buf_bytes - (snd_buf_bytes % instance->tx_channel.stride));
+
+       /* rx buffer size must be a positive multiple of the endpoint maxpacket */
+       maxpacket = usb_maxpacket(usb_dev, instance->rx_channel.endpoint, 0);
+
+       if ((maxpacket < 1) || (maxpacket > UDSL_MAX_BUF_SIZE)) {
+               dev_err(dev, "%s: invalid endpoint %02x!\n", __func__,
+                               usb_pipeendpoint(instance->rx_channel.endpoint));
+               error = -EINVAL;
+               goto fail_unbind;
+       }
+
+       num_packets = max (1U, (rcv_buf_bytes + maxpacket / 2) / maxpacket); /* round */
+
+       if (num_packets * maxpacket > UDSL_MAX_BUF_SIZE)
+               num_packets--;
+
+       instance->rx_channel.buf_size = num_packets * maxpacket;
+       instance->rx_channel.packet_size = maxpacket;
+
+#ifdef DEBUG
+       for (i = 0; i < 2; i++) {
+               struct usbatm_channel *channel = i ?
+                       &instance->tx_channel : &instance->rx_channel;
+
+               dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n", __func__, channel->buf_size, i ? "tx" : "rx", channel);
+       }
+#endif
+
+       /* initialize urbs */
 
        for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
-               struct urb *urb;
                u8 *buffer;
-               unsigned int iso_packets = 0, iso_size = 0;
                struct usbatm_channel *channel = i < num_rcv_urbs ?
                        &instance->rx_channel : &instance->tx_channel;
+               struct urb *urb;
+               unsigned int iso_packets = usb_pipeisoc(channel->endpoint) ? channel->buf_size / channel->packet_size : 0;
 
-               if (usb_pipeisoc(channel->endpoint)) {
-                       /* don't expect iso out endpoints */
-                       iso_size = usb_maxpacket(instance->usb_dev, channel->endpoint, 0);
-                       iso_size -= iso_size % channel->stride; /* alignment */
-                       BUG_ON(!iso_size);
-                       iso_packets = (channel->buf_size - 1) / iso_size + 1;
-               }
+               UDSL_ASSERT(!usb_pipeisoc(channel->endpoint) || usb_pipein(channel->endpoint));
 
                urb = usb_alloc_urb(iso_packets, GFP_KERNEL);
                if (!urb) {
-                       dev_dbg(dev, "%s: no memory for urb %d!\n", __func__, i);
+                       dev_err(dev, "%s: no memory for urb %d!\n", __func__, i);
+                       error = -ENOMEM;
                        goto fail_unbind;
                }
 
                instance->urbs[i] = urb;
 
-               buffer = kmalloc(channel->buf_size, GFP_KERNEL);
+               /* zero the tx padding to avoid leaking information */
+               buffer = kzalloc(channel->buf_size, GFP_KERNEL);
                if (!buffer) {
-                       dev_dbg(dev, "%s: no memory for buffer %d!\n", __func__, i);
+                       dev_err(dev, "%s: no memory for buffer %d!\n", __func__, i);
+                       error = -ENOMEM;
                        goto fail_unbind;
                }
-               memset(buffer, 0, channel->buf_size);
 
                usb_fill_bulk_urb(urb, instance->usb_dev, channel->endpoint,
                                  buffer, channel->buf_size, usbatm_complete, channel);
@@ -1065,9 +1201,8 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
                        urb->transfer_flags = URB_ISO_ASAP;
                        urb->number_of_packets = iso_packets;
                        for (j = 0; j < iso_packets; j++) {
-                               urb->iso_frame_desc[j].offset = iso_size * j;
-                               urb->iso_frame_desc[j].length = min_t(int, iso_size,
-                                                                     channel->buf_size - urb->iso_frame_desc[j].offset);
+                               urb->iso_frame_desc[j].offset = channel->packet_size * j;
+                               urb->iso_frame_desc[j].length = channel->packet_size;
                        }
                }
 
@@ -1079,7 +1214,17 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
                     __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb);
        }
 
-       if (need_heavy && driver->heavy_init) {
+       instance->cached_vpi = ATM_VPI_UNSPEC;
+       instance->cached_vci = ATM_VCI_UNSPEC;
+       instance->cell_buf = kmalloc(instance->rx_channel.stride, GFP_KERNEL);
+
+       if (!instance->cell_buf) {
+               dev_err(dev, "%s: no memory for cell buffer!\n", __func__);
+               error = -ENOMEM;
+               goto fail_unbind;
+       }
+
+       if (!(instance->flags & UDSL_SKIP_HEAVY_INIT) && driver->heavy_init) {
                error = usbatm_heavy_init(instance);
        } else {
                complete(&instance->thread_exited);     /* pretend that heavy_init was run */
@@ -1098,6 +1243,8 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
        if (instance->driver->unbind)
                instance->driver->unbind(instance, intf);
  fail_free:
+       kfree(instance->cell_buf);
+
        for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
                if (instance->urbs[i])
                        kfree(instance->urbs[i]->transfer_buffer);
@@ -1114,6 +1261,7 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
 {
        struct device *dev = &intf->dev;
        struct usbatm_data *instance = usb_get_intfdata(intf);
+       struct usbatm_vcc_data *vcc_data;
        int i;
 
        dev_dbg(dev, "%s entered\n", __func__);
@@ -1125,13 +1273,19 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
 
        usb_set_intfdata(intf, NULL);
 
-       down(&instance->serialize);
+       mutex_lock(&instance->serialize);
+       instance->disconnected = 1;
        if (instance->thread_pid >= 0)
                kill_proc(instance->thread_pid, SIGTERM, 1);
-       up(&instance->serialize);
+       mutex_unlock(&instance->serialize);
 
        wait_for_completion(&instance->thread_exited);
 
+       mutex_lock(&instance->serialize);
+       list_for_each_entry(vcc_data, &instance->vcc_list, list)
+               vcc_release_async(vcc_data->vcc, -EPIPE);
+       mutex_unlock(&instance->serialize);
+
        tasklet_disable(&instance->rx_channel.tasklet);
        tasklet_disable(&instance->tx_channel.tasklet);
 
@@ -1141,6 +1295,14 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
        del_timer_sync(&instance->rx_channel.delay);
        del_timer_sync(&instance->tx_channel.delay);
 
+       /* turn usbatm_[rt]x_process into something close to a no-op */
+       /* no need to take the spinlock */
+       INIT_LIST_HEAD(&instance->rx_channel.list);
+       INIT_LIST_HEAD(&instance->tx_channel.list);
+
+       tasklet_enable(&instance->rx_channel.tasklet);
+       tasklet_enable(&instance->tx_channel.tasklet);
+
        if (instance->atm_dev && instance->driver->atm_stop)
                instance->driver->atm_stop(instance, instance->atm_dev);
 
@@ -1149,19 +1311,13 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
 
        instance->driver_data = NULL;
 
-       /* turn usbatm_[rt]x_process into noop */
-       /* no need to take the spinlock */
-       INIT_LIST_HEAD(&instance->rx_channel.list);
-       INIT_LIST_HEAD(&instance->tx_channel.list);
-
-       tasklet_enable(&instance->rx_channel.tasklet);
-       tasklet_enable(&instance->tx_channel.tasklet);
-
        for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
                kfree(instance->urbs[i]->transfer_buffer);
                usb_free_urb(instance->urbs[i]);
        }
 
+       kfree(instance->cell_buf);
+
        /* ATM finalize */
        if (instance->atm_dev)
                atm_dev_deregister(instance->atm_dev);
@@ -1186,10 +1342,10 @@ static int __init usbatm_usb_init(void)
 
        if ((num_rcv_urbs > UDSL_MAX_RCV_URBS)
            || (num_snd_urbs > UDSL_MAX_SND_URBS)
-           || (rcv_buf_size < 1)
-           || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE)
-           || (snd_buf_size < 1)
-           || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE))
+           || (rcv_buf_bytes < 1)
+           || (rcv_buf_bytes > UDSL_MAX_BUF_SIZE)
+           || (snd_buf_bytes < 1)
+           || (snd_buf_bytes > UDSL_MAX_BUF_SIZE))
                return -EINVAL;
 
        return 0;
index 1adacd60d713fc24815cd8fd1141d3852ba79e33..ff8551e933723c25e16f9524a88458e413e4454b 100644 (file)
 #ifndef        _USBATM_H_
 #define        _USBATM_H_
 
-#include <linux/config.h>
-
-/*
-#define VERBOSE_DEBUG
-*/
-
 #include <asm/semaphore.h>
 #include <linux/atm.h>
 #include <linux/atmdev.h>
 #include <linux/completion.h>
 #include <linux/device.h>
+#include <linux/kernel.h>
 #include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/stringify.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
+
+/*
+#define VERBOSE_DEBUG
+*/
 
 #ifdef DEBUG
 #define UDSL_ASSERT(x) BUG_ON(!(x))
        dev_info(&(instance)->usb_intf->dev , format , ## arg)
 #define usb_warn(instance, format, arg...)     \
        dev_warn(&(instance)->usb_intf->dev , format , ## arg)
+#ifdef DEBUG
 #define usb_dbg(instance, format, arg...)      \
-       dev_dbg(&(instance)->usb_intf->dev , format , ## arg)
+        dev_printk(KERN_DEBUG , &(instance)->usb_intf->dev , format , ## arg)
+#else
+#define usb_dbg(instance, format, arg...)      \
+       do {} while (0)
+#endif
 
 /* FIXME: move to dev_* once ATM is driver model aware */
 #define atm_printk(level, instance, format, arg...)    \
 #ifdef DEBUG
 #define atm_dbg(instance, format, arg...)      \
        atm_printk(KERN_DEBUG, instance , format , ## arg)
+#define atm_rldbg(instance, format, arg...)    \
+       if (printk_ratelimit())                         \
+               atm_printk(KERN_DEBUG, instance , format , ## arg)
 #else
 #define atm_dbg(instance, format, arg...)      \
        do {} while (0)
+#define atm_rldbg(instance, format, arg...)    \
+       do {} while (0)
 #endif
 
 
+/* flags, set by mini-driver in bind() */
+
+#define UDSL_SKIP_HEAVY_INIT   (1<<0)
+#define UDSL_USE_ISOC          (1<<1)
+#define UDSL_IGNORE_EILSEQ     (1<<2)
+
+
 /* mini driver */
 
 struct usbatm_data;
@@ -86,16 +103,11 @@ struct usbatm_data;
 */
 
 struct usbatm_driver {
-       struct module *owner;
-
        const char *driver_name;
 
-       /*
-       *  init device ... can sleep, or cause probe() failure.  Drivers with a heavy_init
-       *  method can avoid having it called by setting need_heavy_init to zero.
-       */
+       /* init device ... can sleep, or cause probe() failure */
         int (*bind) (struct usbatm_data *, struct usb_interface *,
-                    const struct usb_device_id *id, int *need_heavy_init);
+                    const struct usb_device_id *id);
 
        /* additional device initialization that is too slow to be done in probe() */
         int (*heavy_init) (struct usbatm_data *, struct usb_interface *);
@@ -109,8 +121,9 @@ struct usbatm_driver {
        /* cleanup ATM device ... can sleep, but can't fail */
        void (*atm_stop) (struct usbatm_data *, struct atm_dev *);
 
-        int in;                /* rx endpoint */
-        int out;       /* tx endpoint */
+        int bulk_in;   /* bulk rx endpoint */
+        int isoc_in;   /* isochronous rx endpoint */
+        int bulk_out;  /* bulk tx endpoint */
 
        unsigned rx_padding;
        unsigned tx_padding;
@@ -125,6 +138,7 @@ struct usbatm_channel {
        int endpoint;                   /* usb pipe */
        unsigned int stride;            /* ATM cell size + padding */
        unsigned int buf_size;          /* urb buffer size */
+       unsigned int packet_size;       /* endpoint maxpacket */
        spinlock_t lock;
        struct list_head list;
        struct tasklet_struct tasklet;
@@ -143,6 +157,7 @@ struct usbatm_data {
        struct usbatm_driver *driver;
        void *driver_data;
        char driver_name[16];
+       unsigned int flags; /* set by mini-driver in bind() */
 
        /* USB device */
        struct usb_device *usb_dev;
@@ -157,7 +172,8 @@ struct usbatm_data {
         ********************************/
 
        struct kref refcount;
-       struct semaphore serialize;
+       struct mutex serialize;
+       int disconnected;
 
        /* heavy init */
        int thread_pid;
@@ -171,7 +187,14 @@ struct usbatm_data {
        struct usbatm_channel tx_channel;
 
        struct sk_buff_head sndqueue;
-       struct sk_buff *current_skb;                    /* being emptied */
+       struct sk_buff *current_skb;    /* being emptied */
+
+       struct usbatm_vcc_data *cached_vcc;
+       int cached_vci;
+       short cached_vpi;
+
+       unsigned char *cell_buf;        /* holds partial rx cell */
+       unsigned int buf_usage;
 
        struct urb *urbs[0];
 };
index 5c76e3aaaa5e9aaa290936da377ed574011500c4..42d6823b82b3d4efac2658bba02302c48f9baff1 100644 (file)
@@ -41,6 +41,8 @@ XUSBATM_PARM(rx_endpoint, unsigned char, byte, "rx endpoint number");
 XUSBATM_PARM(tx_endpoint, unsigned char, byte, "tx endpoint number");
 XUSBATM_PARM(rx_padding, unsigned char, byte, "rx padding (default 0)");
 XUSBATM_PARM(tx_padding, unsigned char, byte, "tx padding (default 0)");
+XUSBATM_PARM(rx_altsetting, unsigned char, byte, "rx altsetting (default 0)");
+XUSBATM_PARM(tx_altsetting, unsigned char, byte, "rx altsetting (default 0)");
 
 static const char xusbatm_driver_name[] = "xusbatm";
 
@@ -48,82 +50,118 @@ static struct usbatm_driver xusbatm_drivers[XUSBATM_DRIVERS_MAX];
 static struct usb_device_id xusbatm_usb_ids[XUSBATM_DRIVERS_MAX + 1];
 static struct usb_driver xusbatm_usb_driver;
 
-static int usb_intf_has_ep(const struct usb_interface *intf, u8 ep)
+static struct usb_interface *xusbatm_find_intf (struct usb_device *usb_dev, int altsetting, u8 ep)
 {
+       struct usb_host_interface *alt;
+       struct usb_interface *intf;
        int i, j;
 
-       for (i = 0; i < intf->num_altsetting; i++) {
-               struct usb_host_interface *alt = intf->altsetting;
-               for (j = 0; j < alt->desc.bNumEndpoints; j++)
-                       if ((alt->endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) == ep)
-                               return 1;
+       for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++)
+               if ((intf = usb_dev->actconfig->interface[i]) && (alt = usb_altnum_to_altsetting(intf, altsetting)))
+                       for (j = 0; j < alt->desc.bNumEndpoints; j++)
+                               if (alt->endpoint[j].desc.bEndpointAddress == ep)
+                                       return intf;
+       return NULL;
+}
+
+static int xusbatm_capture_intf (struct usbatm_data *usbatm, struct usb_device *usb_dev,
+               struct usb_interface *intf, int altsetting, int claim)
+{
+       int ifnum = intf->altsetting->desc.bInterfaceNumber;
+       int ret;
+
+       if (claim && (ret = usb_driver_claim_interface(&xusbatm_usb_driver, intf, usbatm))) {
+               usb_err(usbatm, "%s: failed to claim interface %2d (%d)!\n", __func__, ifnum, ret);
+               return ret;
+       }
+       if ((ret = usb_set_interface(usb_dev, ifnum, altsetting))) {
+               usb_err(usbatm, "%s: altsetting %2d for interface %2d failed (%d)!\n", __func__, altsetting, ifnum, ret);
+               return ret;
        }
        return 0;
 }
 
-static int xusbatm_bind(struct usbatm_data *usbatm_instance,
-                       struct usb_interface *intf, const struct usb_device_id *id,
-                       int *need_heavy_init)
+static void xusbatm_release_intf (struct usb_device *usb_dev, struct usb_interface *intf, int claimed)
+{
+       if (claimed) {
+               usb_set_intfdata(intf, NULL);
+               usb_driver_release_interface(&xusbatm_usb_driver, intf);
+       }
+}
+
+static int xusbatm_bind(struct usbatm_data *usbatm,
+                       struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct usb_device *usb_dev = interface_to_usbdev(intf);
        int drv_ix = id - xusbatm_usb_ids;
-       int rx_ep_present = usb_intf_has_ep(intf, rx_endpoint[drv_ix]);
-       int tx_ep_present = usb_intf_has_ep(intf, tx_endpoint[drv_ix]);
-       u8 searched_ep = rx_ep_present ? tx_endpoint[drv_ix] : rx_endpoint[drv_ix];
-       int i, ret;
-
-       usb_dbg(usbatm_instance, "%s: binding driver %d: vendor %#x product %#x"
-               " rx: ep %#x padd %d tx: ep %#x padd %d\n",
+       int rx_alt = rx_altsetting[drv_ix];
+       int tx_alt = tx_altsetting[drv_ix];
+       struct usb_interface *rx_intf = xusbatm_find_intf(usb_dev, rx_alt, rx_endpoint[drv_ix]);
+       struct usb_interface *tx_intf = xusbatm_find_intf(usb_dev, tx_alt, tx_endpoint[drv_ix]);
+       int ret;
+
+       usb_dbg(usbatm, "%s: binding driver %d: vendor %04x product %04x"
+               " rx: ep %02x padd %d alt %2d tx: ep %02x padd %d alt %2d\n",
                __func__, drv_ix, vendor[drv_ix], product[drv_ix],
-               rx_endpoint[drv_ix], rx_padding[drv_ix],
-               tx_endpoint[drv_ix], tx_padding[drv_ix]);
+               rx_endpoint[drv_ix], rx_padding[drv_ix], rx_alt,
+               tx_endpoint[drv_ix], tx_padding[drv_ix], tx_alt);
+
+       if (!rx_intf || !tx_intf) {
+               if (!rx_intf)
+                       usb_dbg(usbatm, "%s: no interface contains endpoint %02x in altsetting %2d\n",
+                               __func__, rx_endpoint[drv_ix], rx_alt);
+               if (!tx_intf)
+                       usb_dbg(usbatm, "%s: no interface contains endpoint %02x in altsetting %2d\n",
+                               __func__, tx_endpoint[drv_ix], tx_alt);
+               return -ENODEV;
+       }
 
-       if (!rx_ep_present && !tx_ep_present) {
-               usb_dbg(usbatm_instance, "%s: intf #%d has neither rx (%#x) nor tx (%#x) endpoint\n",
-                       __func__, intf->altsetting->desc.bInterfaceNumber,
-                       rx_endpoint[drv_ix], tx_endpoint[drv_ix]);
+       if ((rx_intf != intf) && (tx_intf != intf))
                return -ENODEV;
+
+       if ((rx_intf == tx_intf) && (rx_alt != tx_alt)) {
+               usb_err(usbatm, "%s: altsettings clash on interface %2d (%2d vs %2d)!\n", __func__,
+                               rx_intf->altsetting->desc.bInterfaceNumber, rx_alt, tx_alt);
+               return -EINVAL;
        }
 
-       if (rx_ep_present && tx_ep_present)
-               return 0;
+       usb_dbg(usbatm, "%s: rx If#=%2d; tx If#=%2d\n", __func__,
+                       rx_intf->altsetting->desc.bInterfaceNumber,
+                       tx_intf->altsetting->desc.bInterfaceNumber);
 
-       for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
-               struct usb_interface *cur_if = usb_dev->actconfig->interface[i];
-
-               if (cur_if != intf && usb_intf_has_ep(cur_if, searched_ep)) {
-                       ret = usb_driver_claim_interface(&xusbatm_usb_driver,
-                                                        cur_if, usbatm_instance);
-                       if (!ret)
-                               usb_err(usbatm_instance, "%s: failed to claim interface #%d (%d)\n",
-                                       __func__, cur_if->altsetting->desc.bInterfaceNumber, ret);
-                       return ret;
-               }
+       if ((ret = xusbatm_capture_intf(usbatm, usb_dev, rx_intf, rx_alt, rx_intf != intf)))
+               return ret;
+
+       if ((tx_intf != rx_intf) && (ret = xusbatm_capture_intf(usbatm, usb_dev, tx_intf, tx_alt, tx_intf != intf))) {
+               xusbatm_release_intf(usb_dev, rx_intf, rx_intf != intf);
+               return ret;
        }
 
-       usb_err(usbatm_instance, "%s: no interface has endpoint %#x\n",
-               __func__, searched_ep);
-       return -ENODEV;
+       return 0;
 }
 
-static void xusbatm_unbind(struct usbatm_data *usbatm_instance,
+static void xusbatm_unbind(struct usbatm_data *usbatm,
                           struct usb_interface *intf)
 {
        struct usb_device *usb_dev = interface_to_usbdev(intf);
        int i;
-       usb_dbg(usbatm_instance, "%s entered\n", __func__);
+
+       usb_dbg(usbatm, "%s entered\n", __func__);
 
        for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
-               struct usb_interface *cur_if = usb_dev->actconfig->interface[i];
-               usb_set_intfdata(cur_if, NULL);
-               usb_driver_release_interface(&xusbatm_usb_driver, cur_if);
+               struct usb_interface *cur_intf = usb_dev->actconfig->interface[i];
+
+               if (cur_intf && (usb_get_intfdata(cur_intf) == usbatm)) {
+                       usb_set_intfdata(cur_intf, NULL);
+                       usb_driver_release_interface(&xusbatm_usb_driver, cur_intf);
+               }
        }
 }
 
-static int xusbatm_atm_start(struct usbatm_data *usbatm_instance,
+static int xusbatm_atm_start(struct usbatm_data *usbatm,
                             struct atm_dev *atm_dev)
 {
-       atm_dbg(usbatm_instance, "%s entered\n", __func__);
+       atm_dbg(usbatm, "%s entered\n", __func__);
 
        /* use random MAC as we've no way to get it from the device */
        random_ether_addr(atm_dev->esi);
@@ -161,18 +199,19 @@ static int __init xusbatm_init(void)
        }
 
        for (i = 0; i < num_vendor; i++) {
+               rx_endpoint[i] |= USB_DIR_IN;
+               tx_endpoint[i] &= USB_ENDPOINT_NUMBER_MASK;
+
                xusbatm_usb_ids[i].match_flags  = USB_DEVICE_ID_MATCH_DEVICE;
                xusbatm_usb_ids[i].idVendor     = vendor[i];
                xusbatm_usb_ids[i].idProduct    = product[i];
 
-
-               xusbatm_drivers[i].owner        = THIS_MODULE;
                xusbatm_drivers[i].driver_name  = xusbatm_driver_name;
                xusbatm_drivers[i].bind         = xusbatm_bind;
                xusbatm_drivers[i].unbind       = xusbatm_unbind;
                xusbatm_drivers[i].atm_start    = xusbatm_atm_start;
-               xusbatm_drivers[i].in           = rx_endpoint[i];
-               xusbatm_drivers[i].out          = tx_endpoint[i];
+               xusbatm_drivers[i].bulk_in      = rx_endpoint[i];
+               xusbatm_drivers[i].bulk_out     = tx_endpoint[i];
                xusbatm_drivers[i].rx_padding   = rx_padding[i];
                xusbatm_drivers[i].tx_padding   = tx_padding[i];
        }
index b9fd39fd1b5b3c37c9a8dc6c729a20bfc6b39fba..97bdeb1c2181650428841826f1c185f53ee81be0 100644 (file)
@@ -1014,8 +1014,13 @@ static void acm_disconnect(struct usb_interface *intf)
        }
 
        down(&open_sem);
+       if (!usb_get_intfdata(intf)) {
+               up(&open_sem);
+               return;
+       }
        acm->dev = NULL;
-       usb_set_intfdata (intf, NULL);
+       usb_set_intfdata(acm->control, NULL);
+       usb_set_intfdata(acm->data, NULL);
 
        tasklet_disable(&acm->urb_task);
 
@@ -1036,7 +1041,7 @@ static void acm_disconnect(struct usb_interface *intf)
        for (i = 0; i < ACM_NRB; i++)
                usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
 
-       usb_driver_release_interface(&acm_driver, acm->data);
+       usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf);
 
        if (!acm->used) {
                acm_tty_unregister(acm);
index dba4cc0260770ebf8d6c39963cd8345c80a98b2a..d34848ac30b0a9571db2dd6cd596cdf139b5c8df 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright (c) 2000 Vojtech Pavlik   <vojtech@suse.cz>
  # Copyright (c) 2001 Pete Zaitcev     <zaitcev@redhat.com>
  # Copyright (c) 2001 David Paschal    <paschal@rcsis.com>
+ * Copyright (c) 2006 Oliver Neukum    <oliver@neukum.name>
  *
  * USB Printer Device Class driver for USB printers and printer cables
  *
@@ -273,13 +274,16 @@ static void usblp_bulk_read(struct urb *urb, struct pt_regs *regs)
 {
        struct usblp *usblp = urb->context;
 
-       if (!usblp || !usblp->dev || !usblp->used || !usblp->present)
+       if (unlikely(!usblp || !usblp->dev || !usblp->used))
                return;
 
+       if (unlikely(!usblp->present))
+               goto unplug;
        if (unlikely(urb->status))
                warn("usblp%d: nonzero read/write bulk status received: %d",
                        usblp->minor, urb->status);
        usblp->rcomplete = 1;
+unplug:
        wake_up_interruptible(&usblp->wait);
 }
 
@@ -287,13 +291,15 @@ static void usblp_bulk_write(struct urb *urb, struct pt_regs *regs)
 {
        struct usblp *usblp = urb->context;
 
-       if (!usblp || !usblp->dev || !usblp->used || !usblp->present)
+       if (unlikely(!usblp || !usblp->dev || !usblp->used))
                return;
-
+       if (unlikely(!usblp->present))
+               goto unplug;
        if (unlikely(urb->status))
                warn("usblp%d: nonzero read/write bulk status received: %d",
                        usblp->minor, urb->status);
        usblp->wcomplete = 1;
+unplug:
        wake_up_interruptible(&usblp->wait);
 }
 
@@ -627,9 +633,8 @@ done:
 
 static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
-       DECLARE_WAITQUEUE(wait, current);
        struct usblp *usblp = file->private_data;
-       int timeout, err = 0, transfer_length = 0;
+       int timeout, rv, err = 0, transfer_length = 0;
        size_t writecount = 0;
 
        while (writecount < count) {
@@ -641,24 +646,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                        }
 
                        timeout = USBLP_WRITE_TIMEOUT;
-                       add_wait_queue(&usblp->wait, &wait);
-                       while ( 1==1 ) {
 
-                               if (signal_pending(current)) {
-                                       remove_wait_queue(&usblp->wait, &wait);
-                                       return writecount ? writecount : -EINTR;
-                               }
-                               set_current_state(TASK_INTERRUPTIBLE);
-                               if (timeout && !usblp->wcomplete) {
-                                       timeout = schedule_timeout(timeout);
-                               } else {
-                                       set_current_state(TASK_RUNNING);
-                                       break;
-                               }
-                       }
-                       remove_wait_queue(&usblp->wait, &wait);
+                       rv = wait_event_interruptible_timeout(usblp->wait, usblp->wcomplete || !usblp->present , timeout);
+                       if (rv < 0)
+                               return writecount ? writecount : -EINTR;
                }
-
                down (&usblp->sem);
                if (!usblp->present) {
                        up (&usblp->sem);
@@ -724,7 +716,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
 static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 {
        struct usblp *usblp = file->private_data;
-       DECLARE_WAITQUEUE(wait, current);
+       int rv;
 
        if (!usblp->bidir)
                return -EINVAL;
@@ -742,26 +734,13 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
                        count = -EAGAIN;
                        goto done;
                }
-
-               add_wait_queue(&usblp->wait, &wait);
-               while (1==1) {
-                       if (signal_pending(current)) {
-                               count = -EINTR;
-                               remove_wait_queue(&usblp->wait, &wait);
-                               goto done;
-                       }
-                       up (&usblp->sem);
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       if (!usblp->rcomplete) {
-                               schedule();
-                       } else {
-                               set_current_state(TASK_RUNNING);
-                               down(&usblp->sem);
-                               break;
-                       }
-                       down (&usblp->sem);
+               up(&usblp->sem);
+               rv = wait_event_interruptible(usblp->wait, usblp->rcomplete || !usblp->present);
+               down(&usblp->sem);
+               if (rv < 0) {
+                       count = -EINTR;
+                       goto done;
                }
-               remove_wait_queue(&usblp->wait, &wait);
        }
 
        if (!usblp->present) {
@@ -874,11 +853,10 @@ static int usblp_probe(struct usb_interface *intf,
 
        /* Malloc and start initializing usblp structure so we can use it
         * directly. */
-       if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
+       if (!(usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL))) {
                err("out of memory for usblp");
                goto abort;
        }
-       memset(usblp, 0, sizeof(struct usblp));
        usblp->dev = dev;
        init_MUTEX (&usblp->sem);
        init_waitqueue_head(&usblp->wait);
@@ -1214,10 +1192,9 @@ static int __init usblp_init(void)
 {
        int retval;
        retval = usb_register(&usblp_driver);
-       if (retval)
-               goto out;
-       info(DRIVER_VERSION ": " DRIVER_DESC);
-out:
+       if (!retval)
+               info(DRIVER_VERSION ": " DRIVER_DESC);
+
        return retval;
 }
 
index 319de03944e7a39d9d0bac12a46afc4f8c32a023..7135e542679d73431d145cee917da3fc18a492f2 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/ctype.h>
 #include <linux/device.h>
 #include <asm/byteorder.h>
+#include <asm/scatterlist.h>
 
 #include "hcd.h"       /* for usbcore internals */
 #include "usb.h"
index 081796726b951bf449b8b827b970cf7eec1b8571..dad4d8fd8180afc8ee779a04b380a7d364cdc9db 100644 (file)
@@ -468,6 +468,7 @@ int usb_unlink_urb(struct urb *urb)
  */
 void usb_kill_urb(struct urb *urb)
 {
+       might_sleep();
        if (!(urb && urb->dev && urb->dev->bus && urb->dev->bus->op))
                return;
        spin_lock_irq(&urb->lock);
index 9a4edc5657aa695cb7f98030084433f6369435c9..0aab7d24c768d03c99c5a67aa154bf2df1e4e640 100644 (file)
@@ -135,6 +135,7 @@ struct dev_data {
                                        setup_out_ready : 1,
                                        setup_out_error : 1,
                                        setup_abort : 1;
+       unsigned                        setup_wLength;
 
        /* the rest is basically write-once */
        struct usb_config_descriptor    *config, *hs_config;
@@ -942,6 +943,7 @@ static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
        }
        req->complete = ep0_complete;
        req->length = len;
+       req->zero = 0;
        return 0;
 }
 
@@ -1161,10 +1163,13 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                                spin_unlock_irq (&dev->lock);
                                if (copy_from_user (dev->req->buf, buf, len))
                                        retval = -EFAULT;
-                               else
+                               else {
+                                       if (len < dev->setup_wLength)
+                                               dev->req->zero = 1;
                                        retval = usb_ep_queue (
                                                dev->gadget->ep0, dev->req,
                                                GFP_KERNEL);
+                               }
                                if (retval < 0) {
                                        spin_lock_irq (&dev->lock);
                                        clean_req (dev->gadget->ep0, dev->req);
@@ -1483,6 +1488,7 @@ unrecognized:
 delegate:
                        dev->setup_in = (ctrl->bRequestType & USB_DIR_IN)
                                                ? 1 : 0;
+                       dev->setup_wLength = w_length;
                        dev->setup_out_ready = 0;
                        dev->setup_out_error = 0;
                        value = 0;
index c32e1f7476da46d67b4e2f8336ab8cd5929b1b75..67b13ab2f3f5a18ef80456fc9362a701777ce797 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
index 2fc110d3ad5ab05b960578280f108de6304b9502..ae7a1c0f57488ca8f28533d767a21e61f8ee7143 100644 (file)
@@ -165,8 +165,8 @@ static unsigned buflen = 4096;
 static unsigned qlen = 32;
 static unsigned pattern = 0;
 
-module_param (buflen, uint, S_IRUGO|S_IWUSR);
-module_param (qlen, uint, S_IRUGO|S_IWUSR);
+module_param (buflen, uint, S_IRUGO);
+module_param (qlen, uint, S_IRUGO);
 module_param (pattern, uint, S_IRUGO|S_IWUSR);
 
 /*
@@ -1127,8 +1127,10 @@ zero_unbind (struct usb_gadget *gadget)
        DBG (dev, "unbind\n");
 
        /* we've already been disconnected ... no i/o is active */
-       if (dev->req)
+       if (dev->req) {
+               dev->req->length = USB_BUFSIZ;
                free_ep_req (gadget->ep0, dev->req);
+       }
        del_timer_sync (&dev->resume);
        kfree (dev);
        set_gadget_data (gadget, NULL);
index 08ca0f849dab03ddbf9688aeb1e77dd811dbf8c6..3a6687df559419c0cb6206fca819dc79f21c45eb 100644 (file)
 
 /*-------------------------------------------------------------------------*/
 
-/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
- * off the controller (maybe it can boot from highspeed USB disks).
- */
-static int bios_handoff(struct ehci_hcd *ehci, int where, u32 cap)
-{
-       struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
-
-       /* always say Linux will own the hardware */
-       pci_write_config_byte(pdev, where + 3, 1);
-
-       /* maybe wait a while for BIOS to respond */
-       if (cap & (1 << 16)) {
-               int msec = 5000;
-
-               do {
-                       msleep(10);
-                       msec -= 10;
-                       pci_read_config_dword(pdev, where, &cap);
-               } while ((cap & (1 << 16)) && msec);
-               if (cap & (1 << 16)) {
-                       ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n",
-                               where, cap);
-                       // some BIOS versions seem buggy...
-                       // return 1;
-                       ehci_warn(ehci, "continuing after BIOS bug...\n");
-                       /* disable all SMIs, and clear "BIOS owns" flag */
-                       pci_write_config_dword(pdev, where + 4, 0);
-                       pci_write_config_byte(pdev, where + 2, 0);
-               } else
-                       ehci_dbg(ehci, "BIOS handoff succeeded\n");
-       }
-       return 0;
-}
-
 /* called after powerup, by probe or system-pm "wakeup" */
 static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
 {
        u32                     temp;
        int                     retval;
-       unsigned                count = 256/4;
 
        /* optional debug port, normally in the first BAR */
        temp = pci_find_capability(pdev, 0x0a);
@@ -84,32 +49,9 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
                }
        }
 
-       temp = HCC_EXT_CAPS(readl(&ehci->caps->hcc_params));
-
-       /* EHCI 0.96 and later may have "extended capabilities" */
-       while (temp && count--) {
-               u32             cap;
-
-               pci_read_config_dword(pdev, temp, &cap);
-               ehci_dbg(ehci, "capability %04x at %02x\n", cap, temp);
-               switch (cap & 0xff) {
-               case 1:                 /* BIOS/SMM/... handoff */
-                       if (bios_handoff(ehci, temp, cap) != 0)
-                               return -EOPNOTSUPP;
-                       break;
-               case 0:                 /* illegal reserved capability */
-                       ehci_dbg(ehci, "illegal capability!\n");
-                       cap = 0;
-                       /* FALLTHROUGH */
-               default:                /* unknown */
-                       break;
-               }
-               temp = (cap >> 8) & 0xff;
-       }
-       if (!count) {
-               ehci_err(ehci, "bogus capabilities ... PCI problems!\n");
-               return -EIO;
-       }
+       /* we expect static quirk code to handle the "extended capabilities"
+        * (currently just BIOS handoff) allowed starting with EHCI 0.96
+        */
 
        /* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */
        retval = pci_set_mwi(pdev);
index 57e77374d228dd083053b78a26d331a44c4e20cd..ebcca97006712e3da3df4b8508f0fbf51dcd726d 100644 (file)
@@ -1063,6 +1063,7 @@ sitd_slot_ok (
 
                /* for IN, check CSPLIT */
                if (stream->c_usecs) {
+                       uf = uframe & 7;
                        max_used = 100 - stream->c_usecs;
                        do {
                                tmp = 1 << uf;
@@ -1843,8 +1844,7 @@ done:
 #else
 
 static inline int
-sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
-       unsigned mem_flags)
+sitd_submit (struct ehci_hcd *ehci, struct urb *urb, gfp_t mem_flags)
 {
        ehci_dbg (ehci, "split iso support is disabled\n");
        return -ENOSYS;
index 584b8dc65119f80187efc3aa2368125bfba870f4..972ce04889f8a9d602c060e896c4efa83b2ab1af 100644 (file)
@@ -1420,20 +1420,22 @@ static int isp116x_bus_suspend(struct usb_hcd *hcd)
        int ret = 0;
 
        spin_lock_irqsave(&isp116x->lock, flags);
-
        val = isp116x_read_reg32(isp116x, HCCONTROL);
+
        switch (val & HCCONTROL_HCFS) {
        case HCCONTROL_USB_OPER:
+               spin_unlock_irqrestore(&isp116x->lock, flags);
                val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
                val |= HCCONTROL_USB_SUSPEND;
                if (device_may_wakeup(&hcd->self.root_hub->dev))
                        val |= HCCONTROL_RWE;
                /* Wait for usb transfers to finish */
-               mdelay(2);
+               msleep(2);
+               spin_lock_irqsave(&isp116x->lock, flags);
                isp116x_write_reg32(isp116x, HCCONTROL, val);
+               spin_unlock_irqrestore(&isp116x->lock, flags);
                /* Wait for devices to suspend */
-               mdelay(5);
-       case HCCONTROL_USB_SUSPEND:
+               msleep(5);
                break;
        case HCCONTROL_USB_RESUME:
                isp116x_write_reg32(isp116x, HCCONTROL,
@@ -1441,12 +1443,11 @@ static int isp116x_bus_suspend(struct usb_hcd *hcd)
                                    HCCONTROL_USB_RESET);
        case HCCONTROL_USB_RESET:
                ret = -EBUSY;
+       default:                /* HCCONTROL_USB_SUSPEND */
+               spin_unlock_irqrestore(&isp116x->lock, flags);
                break;
-       default:
-               ret = -EINVAL;
        }
 
-       spin_unlock_irqrestore(&isp116x->lock, flags);
        return ret;
 }
 
@@ -1715,9 +1716,9 @@ static struct platform_driver isp116x_driver = {
        .remove = isp116x_remove,
        .suspend = isp116x_suspend,
        .resume = isp116x_resume,
-       .driver = {
-               .name = (char *)hcd_name,
-       },
+       .driver = {
+                  .name = (char *)hcd_name,
+                  },
 };
 
 /*-----------------------------------------------------------------*/
index 77cd6ac07e3c5d4076129c13aad23211197db4ab..db280ca7b7a0f1c0ad7444fa38801e40cc12eccb 100644 (file)
@@ -67,7 +67,7 @@ static void au1xxx_stop_hc(struct platform_device *dev)
               ": stopping Au1xxx OHCI USB Controller\n");
 
        /* Disable clock */
-       au_writel(readl((void *)USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
+       au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
 }
 
 
index 3ef2c0cdf1db2fe26c6235ea3410a36e543be617..e9e5bc178cef2e9a71eb2e70e96ced328ec7d00d 100644 (file)
@@ -190,7 +190,7 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
                        msleep(10);
                }
                if (wait_time <= 0)
-                       printk(KERN_WARNING "%s %s: early BIOS handoff "
+                       printk(KERN_WARNING "%s %s: BIOS handoff "
                                        "failed (BIOS bug ?)\n",
                                        pdev->dev.bus_id, "OHCI");
 
@@ -212,8 +212,9 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
 {
        int wait_time, delta;
        void __iomem *base, *op_reg_base;
-       u32 hcc_params, val, temp;
-       u8 cap_length;
+       u32     hcc_params, val;
+       u8      offset, cap_length;
+       int     count = 256/4;
 
        if (!mmio_resource_enabled(pdev, 0))
                return;
@@ -224,51 +225,80 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
 
        cap_length = readb(base);
        op_reg_base = base + cap_length;
+
+       /* EHCI 0.96 and later may have "extended capabilities"
+        * spec section 5.1 explains the bios handoff, e.g. for
+        * booting from USB disk or using a usb keyboard
+        */
        hcc_params = readl(base + EHCI_HCC_PARAMS);
-       hcc_params = (hcc_params >> 8) & 0xff;
-       if (hcc_params) {
-               pci_read_config_dword(pdev,
-                                       hcc_params + EHCI_USBLEGSUP,
-                                       &val);
-               if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
-                       /*
-                        * Ok, BIOS is in smm mode, try to hand off...
+       offset = (hcc_params >> 8) & 0xff;
+       while (offset && count--) {
+               u32             cap;
+               int             msec;
+
+               pci_read_config_dword(pdev, offset, &cap);
+               switch (cap & 0xff) {
+               case 1:                 /* BIOS/SMM/... handoff support */
+                       if ((cap & EHCI_USBLEGSUP_BIOS)) {
+                               pr_debug("%s %s: BIOS handoff\n",
+                                               pdev->dev.bus_id, "EHCI");
+
+                               /* BIOS workaround (?): be sure the
+                                * pre-Linux code receives the SMI
+                                */
+                               pci_read_config_dword(pdev,
+                                               offset + EHCI_USBLEGCTLSTS,
+                                               &val);
+                               pci_write_config_dword(pdev,
+                                               offset + EHCI_USBLEGCTLSTS,
+                                               val | EHCI_USBLEGCTLSTS_SOOE);
+                       }
+
+                       /* always say Linux will own the hardware
+                        * by setting EHCI_USBLEGSUP_OS.
                         */
-                       pci_read_config_dword(pdev,
-                                               hcc_params + EHCI_USBLEGCTLSTS,
-                                               &temp);
-                       pci_write_config_dword(pdev,
-                                               hcc_params + EHCI_USBLEGCTLSTS,
-                                               temp | EHCI_USBLEGCTLSTS_SOOE);
-                       val |= EHCI_USBLEGSUP_OS;
-                       pci_write_config_dword(pdev,
-                                               hcc_params + EHCI_USBLEGSUP,
-                                               val);
+                       pci_write_config_byte(pdev, offset + 3, 1);
 
-                       wait_time = 500;
-                       do {
+                       /* if boot firmware now owns EHCI, spin till
+                        * it hands it over.
+                        */
+                       msec = 5000;
+                       while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
                                msleep(10);
-                               wait_time -= 10;
-                               pci_read_config_dword(pdev,
-                                               hcc_params + EHCI_USBLEGSUP,
-                                               &val);
-                       } while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
-                       if (!wait_time) {
-                               /*
-                                * well, possibly buggy BIOS...
+                               msec -= 10;
+                               pci_read_config_dword(pdev, offset, &cap);
+                       }
+
+                       if (cap & EHCI_USBLEGSUP_BIOS) {
+                               /* well, possibly buggy BIOS... try to shut
+                                * it down, and hope nothing goes too wrong
                                 */
-                               printk(KERN_WARNING "%s %s: early BIOS handoff "
+                               printk(KERN_WARNING "%s %s: BIOS handoff "
                                                "failed (BIOS bug ?)\n",
                                        pdev->dev.bus_id, "EHCI");
-                               pci_write_config_dword(pdev,
-                                               hcc_params + EHCI_USBLEGSUP,
-                                               EHCI_USBLEGSUP_OS);
-                               pci_write_config_dword(pdev,
-                                               hcc_params + EHCI_USBLEGCTLSTS,
-                                               0);
+                               pci_write_config_byte(pdev, offset + 2, 0);
                        }
+
+                       /* just in case, always disable EHCI SMIs */
+                       pci_write_config_dword(pdev,
+                                       offset + EHCI_USBLEGCTLSTS,
+                                       0);
+                       break;
+               case 0:                 /* illegal reserved capability */
+                       cap = 0;
+                       /* FALLTHROUGH */
+               default:
+                       printk(KERN_WARNING "%s %s: unrecognized "
+                                       "capability %02x\n",
+                                       pdev->dev.bus_id, "EHCI",
+                                       cap & 0xff);
+                       break;
                }
+               offset = (cap >> 8) & 0xff;
        }
+       if (!count)
+               printk(KERN_DEBUG "%s %s: capability loop?\n",
+                               pdev->dev.bus_id, "EHCI");
 
        /*
         * halt EHCI & disable its interrupts in any case
index b6076004a4374d54c3ae641a5f606e8a0c0da529..782398045f9f477fa952294f0d31fbfa959ff5e2 100644 (file)
@@ -672,9 +672,9 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
        /* Low-speed transfers get a different queue, and won't hog the bus.
         * Also, some devices enumerate better without FSBR; the easiest way
         * to do that is to put URBs on the low-speed queue while the device
-        * is in the DEFAULT state. */
+        * isn't in the CONFIGURED state. */
        if (urb->dev->speed == USB_SPEED_LOW ||
-                       urb->dev->state == USB_STATE_DEFAULT)
+                       urb->dev->state != USB_STATE_CONFIGURED)
                skelqh = uhci->skel_ls_control_qh;
        else {
                skelqh = uhci->skel_fs_control_qh;
index a91e72c41415c213b8ece5824c16f4873161dc73..6f7a684c3e076fcc2467766e136a08f2ca6d90c9 100644 (file)
@@ -1307,7 +1307,7 @@ void hid_init_reports(struct hid_device *hid)
        }
 
        if (err)
-               warn("timeout initializing reports\n");
+               warn("timeout initializing reports");
 }
 
 #define USB_VENDOR_ID_WACOM            0x056a
@@ -1453,6 +1453,9 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_CHERRY           0x046a
 #define USB_DEVICE_ID_CHERRY_CYMOTION  0x0023
 
+#define USB_VENDOR_ID_HP               0x03f0
+#define USB_DEVICE_ID_HP_USBHUB_KB     0x020c
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -1566,6 +1569,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET},
        { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
+       { USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
 
        { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_POWERMOUSE, HID_QUIRK_2WHEEL_POWERMOUSE },
@@ -1828,9 +1832,6 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        hid->urbctrl->transfer_dma = hid->ctrlbuf_dma;
        hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
 
-       /* May be needed for some devices */
-       usb_clear_halt(hid->dev, hid->urbin->pipe);
-
        return hid;
 
 fail:
index 4dff8473553dd9fc8eba3ebe33378741c8bc7898..77be6b9a820ff4fddffe0727e8d3f7add23ac63e 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/usb.h>
 #include "hid.h"
 #include <linux/hiddev.h>
-#include <linux/devfs_fs_kernel.h>
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
 #define HIDDEV_MINOR_BASE      0
@@ -832,12 +831,10 @@ static /* const */ struct usb_driver hiddev_driver = {
 
 int __init hiddev_init(void)
 {
-       devfs_mk_dir("usb/hid");
        return usb_register(&hiddev_driver);
 }
 
 void hiddev_exit(void)
 {
        usb_deregister(&hiddev_driver);
-       devfs_remove("usb/hid");
 }
index 3b3c7b4120a26c51fb8e8af875f75aa02a201242..697c5e573a115cbe1d38548448032705f4846543 100644 (file)
@@ -337,6 +337,9 @@ static int touchkit_probe(struct usb_interface *intf,
                         touchkit->data, TOUCHKIT_REPORT_DATA_SIZE,
                         touchkit_irq, touchkit, endpoint->bInterval);
 
+       touchkit->irq->transfer_dma = touchkit->data_dma;
+       touchkit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
        input_register_device(touchkit->input);
 
        usb_set_intfdata(intf, touchkit);
index 1bfc105ad4d6811adda2d403870b591bb33c8a6b..37d2f0ba0319c28e73e688394c27c3f65ab28459 100644 (file)
@@ -59,7 +59,7 @@
 #include "map_to_7segment.h"
 #include "yealink.h"
 
-#define DRIVER_VERSION "yld-20050816"
+#define DRIVER_VERSION "yld-20051230"
 #define DRIVER_AUTHOR "Henk Vergonet"
 #define DRIVER_DESC "Yealink phone driver"
 
@@ -786,16 +786,25 @@ static struct attribute_group yld_attr_group = {
  * Linux interface and usb initialisation
  ******************************************************************************/
 
-static const struct yld_device {
-       u16 idVendor;
-       u16 idProduct;
+struct driver_info {
        char *name;
-} yld_device[] = {
-       { 0x6993, 0xb001, "Yealink usb-p1k" },
 };
 
-static struct usb_device_id usb_table [] = {
-       { USB_INTERFACE_INFO(USB_CLASS_HID, 0, 0) },
+static const struct driver_info info_P1K = {
+       .name   = "Yealink usb-p1k",
+};
+
+static const struct usb_device_id usb_table [] = {
+       {
+               .match_flags            = USB_DEVICE_ID_MATCH_DEVICE |
+                                               USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor               = 0x6993,
+               .idProduct              = 0xb001,
+               .bInterfaceClass        = USB_CLASS_HID,
+               .bInterfaceSubClass     = 0,
+               .bInterfaceProtocol     = 0,
+               .driver_info            = (kernel_ulong_t)&info_P1K
+       },
        { }
 };
 
@@ -842,33 +851,16 @@ static void usb_disconnect(struct usb_interface *intf)
        usb_cleanup(yld, 0);
 }
 
-static int usb_match(struct usb_device *udev)
-{
-       int i;
-       u16 idVendor = le16_to_cpu(udev->descriptor.idVendor);
-       u16 idProduct = le16_to_cpu(udev->descriptor.idProduct);
-
-       for (i = 0; i < ARRAY_SIZE(yld_device); i++) {
-               if ((idVendor == yld_device[i].idVendor) &&
-                   (idProduct == yld_device[i].idProduct))
-                       return i;
-       }
-       return -ENODEV;
-}
-
 static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct usb_device *udev = interface_to_usbdev (intf);
+       struct driver_info *nfo = (struct driver_info *)id->driver_info;
        struct usb_host_interface *interface;
        struct usb_endpoint_descriptor *endpoint;
        struct yealink_dev *yld;
        struct input_dev *input_dev;
        int ret, pipe, i;
 
-       i = usb_match(udev);
-       if (i < 0)
-               return -ENODEV;
-
        interface = intf->cur_altsetting;
        endpoint = &interface->endpoint[0].desc;
        if (!(endpoint->bEndpointAddress & USB_DIR_IN))
@@ -915,7 +907,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
        pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
        ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
        if (ret != USB_PKT_LEN)
-               err("invalid payload size %d, expected %d", ret, USB_PKT_LEN);
+               err("invalid payload size %d, expected %zd", ret, USB_PKT_LEN);
 
        /* initialise irq urb */
        usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
@@ -948,7 +940,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
        strlcat(yld->phys,  "/input0", sizeof(yld->phys));
 
        /* register settings for the input device */
-       input_dev->name = yld_device[i].name;
+       input_dev->name = nfo->name;
        input_dev->phys = yld->phys;
        usb_to_input_id(udev, &input_dev->id);
        input_dev->cdev.dev = &intf->dev;
index 21232ee2974cb56902b3e59c6ef843da4fac169a..0d3d2cc5d7be7dfd67fb4b4b878abeb97683bbc5 100644 (file)
@@ -53,6 +53,21 @@ config USB_DSBR
          To compile this driver as a module, choose M here: the
          module will be called dsbr100.
 
+config USB_ET61X251
+       tristate "USB ET61X[12]51 PC Camera Controller support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want support for cameras based on Etoms ET61X151
+         or ET61X251 PC Camera Controllers.
+
+         See <file:Documentation/usb/et61x251.txt> for more informations.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" to use this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called et61x251.
+
 config USB_IBMCAM
        tristate "USB IBM (Xirlink) C-it Camera support"
        depends on USB && VIDEO_DEV
@@ -209,5 +224,3 @@ config USB_PWC
 
          To compile this driver as a module, choose M here: the
          module will be called pwc.
-
-
index d83adffa925f6c68f82fdae5cb527069a6bc5784..3957aa1be0f2ed6644acdfb248c80537d9a12cd2 100644 (file)
@@ -3,9 +3,11 @@
 #
 
 sn9c102-objs   := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o
+et61x251-objs  := et61x251_core.o et61x251_tas5130d1b.o
 
 obj-$(CONFIG_USB_DABUSB)       += dabusb.o
 obj-$(CONFIG_USB_DSBR)         += dsbr100.o
+obj-$(CONFIG_USB_ET61X251)     += et61x251.o
 obj-$(CONFIG_USB_IBMCAM)       += ibmcam.o usbvideo.o ultracam.o
 obj-$(CONFIG_USB_KONICAWC)     += konicawc.o usbvideo.o
 obj-$(CONFIG_USB_OV511)                += ov511.o
diff --git a/drivers/usb/media/et61x251.h b/drivers/usb/media/et61x251.h
new file mode 100644 (file)
index 0000000..652238f
--- /dev/null
@@ -0,0 +1,220 @@
+/***************************************************************************
+ * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * 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.               *
+ ***************************************************************************/
+
+#ifndef _ET61X251_H_
+#define _ET61X251_H_
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/rwsem.h>
+#include <asm/semaphore.h>
+
+#include "et61x251_sensor.h"
+
+/*****************************************************************************/
+
+#define ET61X251_DEBUG
+#define ET61X251_DEBUG_LEVEL         2
+#define ET61X251_MAX_DEVICES         64
+#define ET61X251_PRESERVE_IMGSCALE   0
+#define ET61X251_FORCE_MUNMAP        0
+#define ET61X251_MAX_FRAMES          32
+#define ET61X251_COMPRESSION_QUALITY 0
+#define ET61X251_URBS                2
+#define ET61X251_ISO_PACKETS         7
+#define ET61X251_ALTERNATE_SETTING   13
+#define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
+#define ET61X251_CTRL_TIMEOUT        100
+
+/*****************************************************************************/
+
+static const struct usb_device_id et61x251_id_table[] = {
+       { USB_DEVICE(0x102c, 0x6151), },
+       { USB_DEVICE(0x102c, 0x6251), },
+       { USB_DEVICE(0x102c, 0x6253), },
+       { USB_DEVICE(0x102c, 0x6254), },
+       { USB_DEVICE(0x102c, 0x6255), },
+       { USB_DEVICE(0x102c, 0x6256), },
+       { USB_DEVICE(0x102c, 0x6257), },
+       { USB_DEVICE(0x102c, 0x6258), },
+       { USB_DEVICE(0x102c, 0x6259), },
+       { USB_DEVICE(0x102c, 0x625a), },
+       { USB_DEVICE(0x102c, 0x625b), },
+       { USB_DEVICE(0x102c, 0x625c), },
+       { USB_DEVICE(0x102c, 0x625d), },
+       { USB_DEVICE(0x102c, 0x625e), },
+       { USB_DEVICE(0x102c, 0x625f), },
+       { USB_DEVICE(0x102c, 0x6260), },
+       { USB_DEVICE(0x102c, 0x6261), },
+       { USB_DEVICE(0x102c, 0x6262), },
+       { USB_DEVICE(0x102c, 0x6263), },
+       { USB_DEVICE(0x102c, 0x6264), },
+       { USB_DEVICE(0x102c, 0x6265), },
+       { USB_DEVICE(0x102c, 0x6266), },
+       { USB_DEVICE(0x102c, 0x6267), },
+       { USB_DEVICE(0x102c, 0x6268), },
+       { USB_DEVICE(0x102c, 0x6269), },
+       { }
+};
+
+ET61X251_SENSOR_TABLE
+
+/*****************************************************************************/
+
+enum et61x251_frame_state {
+       F_UNUSED,
+       F_QUEUED,
+       F_GRABBING,
+       F_DONE,
+       F_ERROR,
+};
+
+struct et61x251_frame_t {
+       void* bufmem;
+       struct v4l2_buffer buf;
+       enum et61x251_frame_state state;
+       struct list_head frame;
+       unsigned long vma_use_count;
+};
+
+enum et61x251_dev_state {
+       DEV_INITIALIZED = 0x01,
+       DEV_DISCONNECTED = 0x02,
+       DEV_MISCONFIGURED = 0x04,
+};
+
+enum et61x251_io_method {
+       IO_NONE,
+       IO_READ,
+       IO_MMAP,
+};
+
+enum et61x251_stream_state {
+       STREAM_OFF,
+       STREAM_INTERRUPT,
+       STREAM_ON,
+};
+
+struct et61x251_sysfs_attr {
+       u8 reg, i2c_reg;
+};
+
+struct et61x251_module_param {
+       u8 force_munmap;
+};
+
+static DECLARE_MUTEX(et61x251_sysfs_lock);
+static DECLARE_RWSEM(et61x251_disconnect);
+
+struct et61x251_device {
+       struct video_device* v4ldev;
+
+       struct et61x251_sensor* sensor;
+
+       struct usb_device* usbdev;
+       struct urb* urb[ET61X251_URBS];
+       void* transfer_buffer[ET61X251_URBS];
+       u8* control_buffer;
+
+       struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES];
+       struct list_head inqueue, outqueue;
+       u32 frame_count, nbuffers, nreadbuffers;
+
+       enum et61x251_io_method io;
+       enum et61x251_stream_state stream;
+
+       struct v4l2_jpegcompression compression;
+
+       struct et61x251_sysfs_attr sysfs;
+       struct et61x251_module_param module_param;
+
+       enum et61x251_dev_state state;
+       u8 users;
+
+       struct semaphore dev_sem, fileop_sem;
+       spinlock_t queue_lock;
+       wait_queue_head_t open, wait_frame, wait_stream;
+};
+
+/*****************************************************************************/
+
+void
+et61x251_attach_sensor(struct et61x251_device* cam,
+                       struct et61x251_sensor* sensor)
+{
+       cam->sensor = sensor;
+       cam->sensor->usbdev = cam->usbdev;
+}
+
+/*****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef ET61X251_DEBUG
+#      define DBG(level, fmt, args...)                                       \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1)                                             \
+                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
+               else if ((level) == 2)                                        \
+                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
+               else if ((level) >= 3)                                        \
+                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
+                                __FUNCTION__, __LINE__ , ## args);           \
+       }                                                                     \
+} while (0)
+#      define KDBG(level, fmt, args...)                                      \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1 || (level) == 2)                             \
+                       pr_info("et61x251: " fmt "\n", ## args);              \
+               else if ((level) == 3)                                        \
+                       pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
+                                __LINE__ , ## args);                         \
+       }                                                                     \
+} while (0)
+#      define V4LDBG(level, name, cmd)                                       \
+do {                                                                          \
+       if (debug >= (level))                                                 \
+               v4l_print_ioctl(name, cmd);                                   \
+} while (0)
+#else
+#      define DBG(level, fmt, args...) do {;} while(0)
+#      define KDBG(level, fmt, args...) do {;} while(0)
+#      define V4LDBG(level, name, cmd) do {;} while(0)
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+
+#endif /* _ET61X251_H_ */
diff --git a/drivers/usb/media/et61x251_core.c b/drivers/usb/media/et61x251_core.c
new file mode 100644 (file)
index 0000000..2c0171a
--- /dev/null
@@ -0,0 +1,2605 @@
+/***************************************************************************
+ * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * 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.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/page-flags.h>
+#include <linux/byteorder/generic.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+#include "et61x251.h"
+
+/*****************************************************************************/
+
+#define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
+                                "PC Camera Controllers"
+#define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
+#define ET61X251_MODULE_LICENSE "GPL"
+#define ET61X251_MODULE_VERSION "1:1.01"
+#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 1)
+
+/*****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, et61x251_id_table);
+
+MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(ET61X251_MODULE_NAME);
+MODULE_VERSION(ET61X251_MODULE_VERSION);
+MODULE_LICENSE(ET61X251_MODULE_LICENSE);
+
+static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1};
+module_param_array(video_nr, short, NULL, 0444);
+MODULE_PARM_DESC(video_nr,
+                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
+                 "\n -1 = use next available (default)"
+                 "\n  n = use minor number n (integer >= 0)"
+                 "\nYou can specify up to "
+                 __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way."
+                 "\nFor example:"
+                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                 "\nthe second registered camera and use auto for the first"
+                 "\none and for every other camera."
+                 "\n");
+
+static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
+                               ET61X251_FORCE_MUNMAP};
+module_param_array(force_munmap, bool, NULL, 0444);
+MODULE_PARM_DESC(force_munmap,
+                 "\n<0|1[,...]> Force the application to unmap previously"
+                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                 "\nthis feature. This parameter is specific for each"
+                 "\ndetected camera."
+                 "\n 0 = do not force memory unmapping"
+                 "\n 1 = force memory unmapping (save memory)"
+                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                 "\n");
+
+#ifdef ET61X251_DEBUG
+static unsigned short debug = ET61X251_DEBUG_LEVEL;
+module_param(debug, ushort, 0644);
+MODULE_PARM_DESC(debug,
+                 "\n<n> Debugging information level, from 0 to 3:"
+                 "\n0 = none (use carefully)"
+                 "\n1 = critical errors"
+                 "\n2 = significant informations"
+                 "\n3 = more verbose messages"
+                 "\nLevel 3 is useful for testing only, when only "
+                 "one device is used."
+                 "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"."
+                 "\n");
+#endif
+
+/*****************************************************************************/
+
+static u32
+et61x251_request_buffers(struct et61x251_device* cam, u32 count,
+                         enum et61x251_io_method io)
+{
+       struct v4l2_pix_format* p = &(cam->sensor->pix_format);
+       struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
+       const size_t imagesize = cam->module_param.force_munmap ||
+                                io == IO_READ ?
+                                (p->width * p->height * p->priv) / 8 :
+                                (r->width * r->height * p->priv) / 8;
+       void* buff = NULL;
+       u32 i;
+
+       if (count > ET61X251_MAX_FRAMES)
+               count = ET61X251_MAX_FRAMES;
+
+       cam->nbuffers = count;
+       while (cam->nbuffers > 0) {
+               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+                       break;
+               cam->nbuffers--;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.index = i;
+               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.length = imagesize;
+               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               cam->frame[i].buf.sequence = 0;
+               cam->frame[i].buf.field = V4L2_FIELD_NONE;
+               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+               cam->frame[i].buf.flags = 0;
+       }
+
+       return cam->nbuffers;
+}
+
+
+static void et61x251_release_buffers(struct et61x251_device* cam)
+{
+       if (cam->nbuffers) {
+               vfree(cam->frame[0].bufmem);
+               cam->nbuffers = 0;
+       }
+       cam->frame_current = NULL;
+}
+
+
+static void et61x251_empty_framequeues(struct et61x251_device* cam)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&cam->inqueue);
+       INIT_LIST_HEAD(&cam->outqueue);
+
+       for (i = 0; i < ET61X251_MAX_FRAMES; i++) {
+               cam->frame[i].state = F_UNUSED;
+               cam->frame[i].buf.bytesused = 0;
+       }
+}
+
+
+static void et61x251_requeue_outqueue(struct et61x251_device* cam)
+{
+       struct et61x251_frame_t *i;
+
+       list_for_each_entry(i, &cam->outqueue, frame) {
+               i->state = F_QUEUED;
+               list_add(&i->frame, &cam->inqueue);
+       }
+
+       INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
+static void et61x251_queue_unusedframes(struct et61x251_device* cam)
+{
+       unsigned long lock_flags;
+       u32 i;
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].state == F_UNUSED) {
+                       cam->frame[i].state = F_QUEUED;
+                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
+                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               }
+}
+
+/*****************************************************************************/
+
+int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       *buff = value;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0) {
+               DBG(3, "Failed to write a register (value 0x%02X, index "
+                      "0x%02X, error %d)", value, index, res);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int et61x251_read_reg(struct et61x251_device* cam, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               DBG(3, "Failed to read a register (index 0x%02X, error %d)",
+                   index, res);
+
+       return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+static int
+et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
+{
+       int i, r;
+
+       for (i = 1; i <= 8; i++) {
+               if (sensor->interface == ET61X251_I2C_3WIRES) {
+                       r = et61x251_read_reg(cam, 0x8e);
+                       if (!(r & 0x02) && (r >= 0))
+                               return 0;
+               } else {
+                       r = et61x251_read_reg(cam, 0x8b);
+                       if (!(r & 0x01) && (r >= 0))
+                               return 0;
+               }
+               if (r < 0)
+                       return -EIO;
+               udelay(8*8); /* minimum for sensors at 400kHz */
+       }
+
+       return -EBUSY;
+}
+
+
+int
+et61x251_i2c_try_read(struct et61x251_device* cam,
+                      struct et61x251_sensor* sensor, u8 address)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       data[0] = address;
+       data[1] = cam->sensor->i2c_slave_id;
+       data[2] = cam->sensor->rsta | 0x10;
+       data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, sensor);
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       if (err)
+               DBG(3, "I2C read failed for %s image sensor", sensor->name);
+
+       PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
+
+       return err ? -1 : (int)data[0];
+}
+
+
+int
+et61x251_i2c_try_write(struct et61x251_device* cam,
+                       struct et61x251_sensor* sensor, u8 address, u8 value)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       data[0] = address;
+       data[1] = cam->sensor->i2c_slave_id;
+       data[2] = cam->sensor->rsta | 0x12;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       data[0] = value;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, sensor);
+
+       if (err)
+               DBG(3, "I2C write failed for %s image sensor", sensor->name);
+
+       PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
+
+       return err ? -1 : 0;
+}
+
+
+int
+et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
+                       u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
+                       u8 data8, u8 address)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       if (!cam->sensor)
+               return -1;
+
+       data[0] = data2;
+       data[1] = data3;
+       data[2] = data4;
+       data[3] = data5;
+       data[4] = data6;
+       data[5] = data7;
+       data[6] = data8;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       data[0] = address;
+       data[1] = cam->sensor->i2c_slave_id;
+       data[2] = cam->sensor->rsta | 0x02 | (n << 4);
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       /* Start writing through the serial interface */
+       data[0] = data1;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, cam->sensor);
+
+       if (err)
+               DBG(3, "I2C raw write failed for %s image sensor",
+                   cam->sensor->name);
+
+       PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "
+             "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"
+             " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address,
+             data1, data2, data3, data4, data5, data6, data7, data8);
+
+       return err ? -1 : 0;
+
+}
+
+
+int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
+{
+       if (!cam->sensor)
+               return -1;
+
+       return et61x251_i2c_try_read(cam, cam->sensor, address);
+}
+
+
+int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
+{
+       if (!cam->sensor)
+               return -1;
+
+       return et61x251_i2c_try_write(cam, cam->sensor, address, value);
+}
+
+/*****************************************************************************/
+
+static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
+{
+       struct et61x251_device* cam = urb->context;
+       struct et61x251_frame_t** f;
+       size_t imagesize;
+       u8 i;
+       int err = 0;
+
+       if (urb->status == -ENOENT)
+               return;
+
+       f = &cam->frame_current;
+
+       if (cam->stream == STREAM_INTERRUPT) {
+               cam->stream = STREAM_OFF;
+               if ((*f))
+                       (*f)->state = F_QUEUED;
+               DBG(3, "Stream interrupted");
+               wake_up_interruptible(&cam->wait_stream);
+       }
+
+       if (cam->state & DEV_DISCONNECTED)
+               return;
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               wake_up_interruptible(&cam->wait_frame);
+               return;
+       }
+
+       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
+               goto resubmit_urb;
+
+       if (!(*f))
+               (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,
+                                 frame);
+
+       imagesize = (cam->sensor->pix_format.width *
+                    cam->sensor->pix_format.height *
+                    cam->sensor->pix_format.priv) / 8;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               unsigned int len, status;
+               void *pos;
+               u8* b1, * b2, sof;
+               const u8 VOID_BYTES = 6;
+               size_t imglen;
+
+               len = urb->iso_frame_desc[i].actual_length;
+               status = urb->iso_frame_desc[i].status;
+               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+               if (status) {
+                       DBG(3, "Error in isochronous frame");
+                       (*f)->state = F_ERROR;
+                       continue;
+               }
+
+               b1 = pos++;
+               b2 = pos++;
+               sof = ((*b1 & 0x3f) == 63);
+               imglen = ((*b1 & 0xc0) << 2) | *b2;
+
+               PDBGG("Isochrnous frame: length %u, #%u i, image length %zu",
+                     len, i, imglen);
+
+               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
+start_of_frame:
+                       if (sof) {
+                               (*f)->state = F_GRABBING;
+                               (*f)->buf.bytesused = 0;
+                               do_gettimeofday(&(*f)->buf.timestamp);
+                               pos += 22;
+                               DBG(3, "SOF detected: new video frame");
+                       }
+
+               if ((*f)->state == F_GRABBING) {
+                       if (sof && (*f)->buf.bytesused) {
+                               if (cam->sensor->pix_format.pixelformat ==
+                                                        V4L2_PIX_FMT_ET61X251)
+                                       goto end_of_frame;
+                               else {
+                                       DBG(3, "Not expected SOF detected "
+                                              "after %lu bytes",
+                                          (unsigned long)(*f)->buf.bytesused);
+                                       (*f)->state = F_ERROR;
+                                       continue;
+                               }
+                       }
+
+                       if ((*f)->buf.bytesused + imglen > imagesize) {
+                               DBG(3, "Video frame size exceeded");
+                               (*f)->state = F_ERROR;
+                               continue;
+                       }
+
+                       pos += VOID_BYTES;
+
+                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen);
+                       (*f)->buf.bytesused += imglen;
+
+                       if ((*f)->buf.bytesused == imagesize) {
+                               u32 b;
+end_of_frame:
+                               b = (*f)->buf.bytesused;
+                               (*f)->state = F_DONE;
+                               (*f)->buf.sequence= ++cam->frame_count;
+                               spin_lock(&cam->queue_lock);
+                               list_move_tail(&(*f)->frame, &cam->outqueue);
+                               if (!list_empty(&cam->inqueue))
+                                       (*f) = list_entry(cam->inqueue.next,
+                                                      struct et61x251_frame_t,
+                                                         frame);
+                               else
+                                       (*f) = NULL;
+                               spin_unlock(&cam->queue_lock);
+                               DBG(3, "Video frame captured: : %lu bytes",
+                                      (unsigned long)(b));
+
+                               if (!(*f))
+                                       goto resubmit_urb;
+
+                               if (sof &&
+                                   cam->sensor->pix_format.pixelformat ==
+                                                        V4L2_PIX_FMT_ET61X251)
+                                       goto start_of_frame;
+                       }
+               }
+       }
+
+resubmit_urb:
+       urb->dev = cam->usbdev;
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0 && err != -EPERM) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "usb_submit_urb() failed");
+       }
+
+       wake_up_interruptible(&cam->wait_frame);
+}
+
+
+static int et61x251_start_transfer(struct et61x251_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       struct urb* urb;
+       const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832,
+                                              864, 896, 920, 956, 980, 1000,
+                                              1022};
+       const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING];
+       s8 i, j;
+       int err = 0;
+
+       for (i = 0; i < ET61X251_URBS; i++) {
+               cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz,
+                                                 GFP_KERNEL);
+               if (!cam->transfer_buffer[i]) {
+                       err = -ENOMEM;
+                       DBG(1, "Not enough memory");
+                       goto free_buffers;
+               }
+       }
+
+       for (i = 0; i < ET61X251_URBS; i++) {
+               urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL);
+               cam->urb[i] = urb;
+               if (!urb) {
+                       err = -ENOMEM;
+                       DBG(1, "usb_alloc_urb() failed");
+                       goto free_urbs;
+               }
+               urb->dev = udev;
+               urb->context = cam;
+               urb->pipe = usb_rcvisocpipe(udev, 1);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->number_of_packets = ET61X251_ISO_PACKETS;
+               urb->complete = et61x251_urb_complete;
+               urb->transfer_buffer = cam->transfer_buffer[i];
+               urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS;
+               urb->interval = 1;
+               for (j = 0; j < ET61X251_ISO_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = psz * j;
+                       urb->iso_frame_desc[j].length = psz;
+               }
+       }
+
+       err = et61x251_write_reg(cam, 0x01, 0x03);
+       err = et61x251_write_reg(cam, 0x00, 0x03);
+       err = et61x251_write_reg(cam, 0x08, 0x03);
+       if (err) {
+               err = -EIO;
+               DBG(1, "I/O hardware error");
+               goto free_urbs;
+       }
+
+       err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING);
+       if (err) {
+               DBG(1, "usb_set_interface() failed");
+               goto free_urbs;
+       }
+
+       cam->frame_current = NULL;
+
+       for (i = 0; i < ET61X251_URBS; i++) {
+               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+               if (err) {
+                       for (j = i-1; j >= 0; j--)
+                               usb_kill_urb(cam->urb[j]);
+                       DBG(1, "usb_submit_urb() failed, error %d", err);
+                       goto free_urbs;
+               }
+       }
+
+       return 0;
+
+free_urbs:
+       for (i = 0; (i < ET61X251_URBS) &&  cam->urb[i]; i++)
+               usb_free_urb(cam->urb[i]);
+
+free_buffers:
+       for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++)
+               kfree(cam->transfer_buffer[i]);
+
+       return err;
+}
+
+
+static int et61x251_stop_transfer(struct et61x251_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       s8 i;
+       int err = 0;
+
+       if (cam->state & DEV_DISCONNECTED)
+               return 0;
+
+       for (i = ET61X251_URBS-1; i >= 0; i--) {
+               usb_kill_urb(cam->urb[i]);
+               usb_free_urb(cam->urb[i]);
+               kfree(cam->transfer_buffer[i]);
+       }
+
+       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+       if (err)
+               DBG(3, "usb_set_interface() failed");
+
+       return err;
+}
+
+
+static int et61x251_stream_interrupt(struct et61x251_device* cam)
+{
+       int err = 0;
+
+       cam->stream = STREAM_INTERRUPT;
+       err = wait_event_timeout(cam->wait_stream,
+                                (cam->stream == STREAM_OFF) ||
+                                (cam->state & DEV_DISCONNECTED),
+                                ET61X251_URB_TIMEOUT);
+       if (cam->state & DEV_DISCONNECTED)
+               return -ENODEV;
+       else if (err) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "URB timeout reached. The camera is misconfigured. To "
+                      "use it, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return err;
+       }
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
+{
+       char str[5];
+       char* endp;
+       unsigned long val;
+
+       if (len < 4) {
+               strncpy(str, buff, len);
+               str[len+1] = '\0';
+       } else {
+               strncpy(str, buff, 4);
+               str[4] = '\0';
+       }
+
+       val = simple_strtoul(str, &endp, 0);
+
+       *count = 0;
+       if (val <= 0xff)
+               *count = (ssize_t)(endp - str);
+       if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
+               *count += 1;
+
+       return (u8)val;
+}
+
+/*
+   NOTE 1: being inside one of the following methods implies that the v4l
+           device exists for sure (see kobjects and reference counters)
+   NOTE 2: buffers are PAGE_SIZE long
+*/
+
+static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+
+       if (down_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               up(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       count = sprintf(buf, "%u\n", cam->sysfs.reg);
+
+       up(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 index;
+       ssize_t count;
+
+       if (down_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               up(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       index = et61x251_strtou8(buf, len, &count);
+       if (index > 0x8e || !count) {
+               up(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       cam->sysfs.reg = index;
+
+       DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);
+       DBG(3, "Written bytes: %zd", count);
+
+       up(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+       int val;
+
+       if (down_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               up(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {
+               up(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       count = sprintf(buf, "%d\n", val);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       up(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 value;
+       ssize_t count;
+       int err;
+
+       if (down_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               up(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       value = et61x251_strtou8(buf, len, &count);
+       if (!count) {
+               up(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       err = et61x251_write_reg(cam, value, cam->sysfs.reg);
+       if (err) {
+               up(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X",
+           cam->sysfs.reg, value);
+       DBG(3, "Written bytes: %zd", count);
+
+       up(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+
+       if (down_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               up(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       up(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 index;
+       ssize_t count;
+
+       if (down_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               up(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       index = et61x251_strtou8(buf, len, &count);
+       if (!count) {
+               up(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       cam->sysfs.i2c_reg = index;
+
+       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
+       DBG(3, "Written bytes: %zd", count);
+
+       up(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+       int val;
+
+       if (down_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               up(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) {
+               up(&et61x251_sysfs_lock);
+               return -ENOSYS;
+       }
+
+       if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
+               up(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       count = sprintf(buf, "%d\n", val);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       up(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 value;
+       ssize_t count;
+       int err;
+
+       if (down_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               up(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if (!(cam->sensor->sysfs_ops & ET61X251_I2C_READ)) {
+               up(&et61x251_sysfs_lock);
+               return -ENOSYS;
+       }
+
+       value = et61x251_strtou8(buf, len, &count);
+       if (!count) {
+               up(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);
+       if (err) {
+               up(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
+           cam->sysfs.i2c_reg, value);
+       DBG(3, "Written bytes: %zd", count);
+
+       up(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
+                         et61x251_show_reg, et61x251_store_reg);
+static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
+                         et61x251_show_val, et61x251_store_val);
+static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+                         et61x251_show_i2c_reg, et61x251_store_i2c_reg);
+static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+                         et61x251_show_i2c_val, et61x251_store_i2c_val);
+
+
+static void et61x251_create_sysfs(struct et61x251_device* cam)
+{
+       struct video_device *v4ldev = cam->v4ldev;
+
+       video_device_create_file(v4ldev, &class_device_attr_reg);
+       video_device_create_file(v4ldev, &class_device_attr_val);
+       if (cam->sensor && cam->sensor->sysfs_ops) {
+               video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+               video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+       }
+}
+#endif /* CONFIG_VIDEO_ADV_DEBUG */
+
+/*****************************************************************************/
+
+static int
+et61x251_set_pix_format(struct et61x251_device* cam,
+                        struct v4l2_pix_format* pix)
+{
+       int r, err = 0;
+
+       if ((r = et61x251_read_reg(cam, 0x12)) < 0)
+               err += r;
+       if (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
+               err += et61x251_write_reg(cam, r & 0xfd, 0x12);
+       else
+               err += et61x251_write_reg(cam, r | 0x02, 0x12);
+
+       return err ? -EIO : 0;
+}
+
+
+static int
+et61x251_set_compression(struct et61x251_device* cam,
+                         struct v4l2_jpegcompression* compression)
+{
+       int r, err = 0;
+
+       if ((r = et61x251_read_reg(cam, 0x12)) < 0)
+               err += r;
+       if (compression->quality == 0)
+               err += et61x251_write_reg(cam, r & 0xfb, 0x12);
+       else
+               err += et61x251_write_reg(cam, r | 0x04, 0x12);
+
+       return err ? -EIO : 0;
+}
+
+
+static int et61x251_set_scale(struct et61x251_device* cam, u8 scale)
+{
+       int r = 0, err = 0;
+
+       r = et61x251_read_reg(cam, 0x12);
+       if (r < 0)
+               err += r;
+
+       if (scale == 1)
+               err += et61x251_write_reg(cam, r & ~0x01, 0x12);
+       else if (scale == 2)
+               err += et61x251_write_reg(cam, r | 0x01, 0x12);
+
+       if (err)
+               return -EIO;
+
+       PDBGG("Scaling factor: %u", scale);
+
+       return 0;
+}
+
+
+static int
+et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
+{
+       struct et61x251_sensor* s = cam->sensor;
+       u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +
+                          s->active_pixel.left),
+           fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +
+                          s->active_pixel.top),
+           fmw_length = (u16)(rect->width),
+           fmw_height = (u16)(rect->height);
+       int err = 0;
+
+       err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69);
+       err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a);
+       err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b);
+       err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c);
+       err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6)
+                                      | ((fmw_length & 0x300) >> 4)
+                                      | ((fmw_height & 0x300) >> 2), 0x6d);
+       if (err)
+               return -EIO;
+
+       PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u",
+             fmw_sx, fmw_sy, fmw_length, fmw_height);
+
+       return 0;
+}
+
+
+static int et61x251_init(struct et61x251_device* cam)
+{
+       struct et61x251_sensor* s = cam->sensor;
+       struct v4l2_control ctrl;
+       struct v4l2_queryctrl *qctrl;
+       struct v4l2_rect* rect;
+       u8 i = 0;
+       int err = 0;
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               init_waitqueue_head(&cam->open);
+               qctrl = s->qctrl;
+               rect = &(s->cropcap.defrect);
+               cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
+       } else { /* use current values */
+               qctrl = s->_qctrl;
+               rect = &(s->_rect);
+       }
+
+       err += et61x251_set_scale(cam, rect->width / s->pix_format.width);
+       err += et61x251_set_crop(cam, rect);
+       if (err)
+               return err;
+
+       if (s->init) {
+               err = s->init(cam);
+               if (err) {
+                       DBG(3, "Sensor initialization failed");
+                       return err;
+               }
+       }
+
+       err += et61x251_set_compression(cam, &cam->compression);
+       err += et61x251_set_pix_format(cam, &s->pix_format);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, &s->pix_format);
+       if (err)
+               return err;
+
+       if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251)
+               DBG(3, "Compressed video format is active, quality %d",
+                   cam->compression.quality);
+       else
+               DBG(3, "Uncompressed video format is active");
+
+       if (s->set_crop)
+               if ((err = s->set_crop(cam, rect))) {
+                       DBG(3, "set_crop() failed");
+                       return err;
+               }
+
+       if (s->set_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (s->qctrl[i].id != 0 &&
+                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
+                               ctrl.id = s->qctrl[i].id;
+                               ctrl.value = qctrl[i].default_value;
+                               err = s->set_ctrl(cam, &ctrl);
+                               if (err) {
+                                       DBG(3, "Set %s control failed",
+                                           s->qctrl[i].name);
+                                       return err;
+                               }
+                               DBG(3, "Image sensor supports '%s' control",
+                                   s->qctrl[i].name);
+                       }
+       }
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               init_MUTEX(&cam->fileop_sem);
+               spin_lock_init(&cam->queue_lock);
+               init_waitqueue_head(&cam->wait_frame);
+               init_waitqueue_head(&cam->wait_stream);
+               cam->nreadbuffers = 2;
+               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
+               memcpy(&(s->_rect), &(s->cropcap.defrect),
+                      sizeof(struct v4l2_rect));
+               cam->state |= DEV_INITIALIZED;
+       }
+
+       DBG(2, "Initialization succeeded");
+       return 0;
+}
+
+
+static void et61x251_release_resources(struct et61x251_device* cam)
+{
+       down(&et61x251_sysfs_lock);
+
+       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+       video_set_drvdata(cam->v4ldev, NULL);
+       video_unregister_device(cam->v4ldev);
+
+       up(&et61x251_sysfs_lock);
+
+       kfree(cam->control_buffer);
+}
+
+/*****************************************************************************/
+
+static int et61x251_open(struct inode* inode, struct file* filp)
+{
+       struct et61x251_device* cam;
+       int err = 0;
+
+       /*
+          This is the only safe way to prevent race conditions with
+          disconnect
+       */
+       if (!down_read_trylock(&et61x251_disconnect))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(video_devdata(filp));
+
+       if (down_interruptible(&cam->dev_sem)) {
+               up_read(&et61x251_disconnect);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               if ((filp->f_flags & O_NONBLOCK) ||
+                   (filp->f_flags & O_NDELAY)) {
+                       err = -EWOULDBLOCK;
+                       goto out;
+               }
+               up(&cam->dev_sem);
+               err = wait_event_interruptible_exclusive(cam->open,
+                                                 cam->state & DEV_DISCONNECTED
+                                                        || !cam->users);
+               if (err) {
+                       up_read(&et61x251_disconnect);
+                       return err;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       up_read(&et61x251_disconnect);
+                       return -ENODEV;
+               }
+               down(&cam->dev_sem);
+       }
+
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               err = et61x251_init(cam);
+               if (err) {
+                       DBG(1, "Initialization failed again. "
+                              "I will retry on next open().");
+                       goto out;
+               }
+               cam->state &= ~DEV_MISCONFIGURED;
+       }
+
+       if ((err = et61x251_start_transfer(cam)))
+               goto out;
+
+       filp->private_data = cam;
+       cam->users++;
+       cam->io = IO_NONE;
+       cam->stream = STREAM_OFF;
+       cam->nbuffers = 0;
+       cam->frame_count = 0;
+       et61x251_empty_framequeues(cam);
+
+       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+
+out:
+       up(&cam->dev_sem);
+       up_read(&et61x251_disconnect);
+       return err;
+}
+
+
+static int et61x251_release(struct inode* inode, struct file* filp)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+
+       down(&cam->dev_sem); /* prevent disconnect() to be called */
+
+       et61x251_stop_transfer(cam);
+
+       et61x251_release_buffers(cam);
+
+       if (cam->state & DEV_DISCONNECTED) {
+               et61x251_release_resources(cam);
+               up(&cam->dev_sem);
+               kfree(cam);
+               return 0;
+       }
+
+       cam->users--;
+       wake_up_interruptible_nr(&cam->open, 1);
+
+       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+
+       up(&cam->dev_sem);
+
+       return 0;
+}
+
+
+static ssize_t
+et61x251_read(struct file* filp, char __user * buf,
+              size_t count, loff_t* f_pos)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_frame_t* f, * i;
+       unsigned long lock_flags;
+       int err = 0;
+
+       if (down_interruptible(&cam->fileop_sem))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               up(&cam->fileop_sem);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               up(&cam->fileop_sem);
+               return -EIO;
+       }
+
+       if (cam->io == IO_MMAP) {
+               DBG(3, "Close and open the device again to choose the read "
+                      "method");
+               up(&cam->fileop_sem);
+               return -EINVAL;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!et61x251_request_buffers(cam, cam->nreadbuffers,
+                                             IO_READ)) {
+                       DBG(1, "read() failed, not enough memory");
+                       up(&cam->fileop_sem);
+                       return -ENOMEM;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (list_empty(&cam->inqueue)) {
+               if (!list_empty(&cam->outqueue))
+                       et61x251_empty_framequeues(cam);
+               et61x251_queue_unusedframes(cam);
+       }
+
+       if (!count) {
+               up(&cam->fileop_sem);
+               return 0;
+       }
+
+       if (list_empty(&cam->outqueue)) {
+               if (filp->f_flags & O_NONBLOCK) {
+                       up(&cam->fileop_sem);
+                       return -EAGAIN;
+               }
+               err = wait_event_interruptible
+                     ( cam->wait_frame,
+                       (!list_empty(&cam->outqueue)) ||
+                       (cam->state & DEV_DISCONNECTED) ||
+                       (cam->state & DEV_MISCONFIGURED) );
+               if (err) {
+                       up(&cam->fileop_sem);
+                       return err;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       up(&cam->fileop_sem);
+                       return -ENODEV;
+               }
+               if (cam->state & DEV_MISCONFIGURED) {
+                       up(&cam->fileop_sem);
+                       return -EIO;
+               }
+       }
+
+       f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame);
+
+       if (count > f->buf.bytesused)
+               count = f->buf.bytesused;
+
+       if (copy_to_user(buf, f->bufmem, count)) {
+               err = -EFAULT;
+               goto exit;
+       }
+       *f_pos += count;
+
+exit:
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_for_each_entry(i, &cam->outqueue, frame)
+               i->state = F_UNUSED;
+       INIT_LIST_HEAD(&cam->outqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       et61x251_queue_unusedframes(cam);
+
+       PDBGG("Frame #%lu, bytes read: %zu",
+             (unsigned long)f->buf.index, count);
+
+       up(&cam->fileop_sem);
+
+       return err ? err : count;
+}
+
+
+static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_frame_t* f;
+       unsigned long lock_flags;
+       unsigned int mask = 0;
+
+       if (down_interruptible(&cam->fileop_sem))
+               return POLLERR;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               goto error;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               goto error;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!et61x251_request_buffers(cam, cam->nreadbuffers,
+                                             IO_READ)) {
+                       DBG(1, "poll() failed, not enough memory");
+                       goto error;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (cam->io == IO_READ) {
+               spin_lock_irqsave(&cam->queue_lock, lock_flags);
+               list_for_each_entry(f, &cam->outqueue, frame)
+                       f->state = F_UNUSED;
+               INIT_LIST_HEAD(&cam->outqueue);
+               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               et61x251_queue_unusedframes(cam);
+       }
+
+       poll_wait(filp, &cam->wait_frame, wait);
+
+       if (!list_empty(&cam->outqueue))
+               mask |= POLLIN | POLLRDNORM;
+
+       up(&cam->fileop_sem);
+
+       return mask;
+
+error:
+       up(&cam->fileop_sem);
+       return POLLERR;
+}
+
+
+static void et61x251_vm_open(struct vm_area_struct* vma)
+{
+       struct et61x251_frame_t* f = vma->vm_private_data;
+       f->vma_use_count++;
+}
+
+
+static void et61x251_vm_close(struct vm_area_struct* vma)
+{
+       /* NOTE: buffers are not freed here */
+       struct et61x251_frame_t* f = vma->vm_private_data;
+       f->vma_use_count--;
+}
+
+
+static struct vm_operations_struct et61x251_vm_ops = {
+       .open = et61x251_vm_open,
+       .close = et61x251_vm_close,
+};
+
+
+static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       unsigned long size = vma->vm_end - vma->vm_start,
+                     start = vma->vm_start;
+       void *pos;
+       u32 i;
+
+       if (down_interruptible(&cam->fileop_sem))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               up(&cam->fileop_sem);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               up(&cam->fileop_sem);
+               return -EIO;
+       }
+
+       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
+               up(&cam->fileop_sem);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == cam->nbuffers) {
+               up(&cam->fileop_sem);
+               return -EINVAL;
+       }
+
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;
+
+       pos = cam->frame[i].bufmem;
+       while (size > 0) { /* size is page-aligned */
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       up(&cam->fileop_sem);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vma->vm_ops = &et61x251_vm_ops;
+       vma->vm_private_data = &cam->frame[i];
+
+       et61x251_vm_open(vma);
+
+       up(&cam->fileop_sem);
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_capability cap = {
+               .driver = "et61x251",
+               .version = ET61X251_MODULE_VERSION_CODE,
+               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING,
+       };
+
+       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+                       sizeof(cap.bus_info));
+
+       if (copy_to_user(arg, &cap, sizeof(cap)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_input i;
+
+       if (copy_from_user(&i, arg, sizeof(i)))
+               return -EFAULT;
+
+       if (i.index)
+               return -EINVAL;
+
+       memset(&i, 0, sizeof(i));
+       strcpy(i.name, "Camera");
+
+       if (copy_to_user(arg, &i, sizeof(i)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_gs_input(struct et61x251_device* cam, void __user * arg)
+{
+       int index;
+
+       if (copy_from_user(&index, arg, sizeof(index)))
+               return -EFAULT;
+
+       if (index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = cam->sensor;
+       struct v4l2_queryctrl qc;
+       u8 i;
+
+       if (copy_from_user(&qc, arg, sizeof(qc)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (qc.id && qc.id == s->qctrl[i].id) {
+                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+                       if (copy_to_user(arg, &qc, sizeof(qc)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+
+static int
+et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = cam->sensor;
+       struct v4l2_control ctrl;
+       int err = 0;
+       u8 i;
+
+       if (!s->get_ctrl && !s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       if (!s->get_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (ctrl.id == s->qctrl[i].id) {
+                               ctrl.value = s->_qctrl[i].default_value;
+                               goto exit;
+                       }
+               return -EINVAL;
+       } else
+               err = s->get_ctrl(cam, &ctrl);
+
+exit:
+       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+               return -EFAULT;
+
+       return err;
+}
+
+
+static int
+et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = cam->sensor;
+       struct v4l2_control ctrl;
+       u8 i;
+       int err = 0;
+
+       if (!s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (ctrl.id == s->qctrl[i].id) {
+                       if (ctrl.value < s->qctrl[i].minimum ||
+                           ctrl.value > s->qctrl[i].maximum)
+                               return -ERANGE;
+                       ctrl.value -= ctrl.value % s->qctrl[i].step;
+                       break;
+               }
+
+       if ((err = s->set_ctrl(cam, &ctrl)))
+               return err;
+
+       s->_qctrl[i].default_value = ctrl.value;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
+
+       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cc->pixelaspect.numerator = 1;
+       cc->pixelaspect.denominator = 1;
+
+       if (copy_to_user(arg, cc, sizeof(*cc)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = cam->sensor;
+       struct v4l2_crop crop = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       };
+
+       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+       if (copy_to_user(arg, &crop, sizeof(crop)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = cam->sensor;
+       struct v4l2_crop crop;
+       struct v4l2_rect* rect;
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_pix_format* pix_format = &(s->pix_format);
+       u8 scale;
+       const enum et61x251_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&crop, arg, sizeof(crop)))
+               return -EFAULT;
+
+       rect = &(crop.c);
+
+       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_CROP failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       /* Preserve R,G or B origin */
+       rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
+       rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
+
+       if (rect->width < 4)
+               rect->width = 4;
+       if (rect->height < 4)
+               rect->height = 4;
+       if (rect->width > bounds->width)
+               rect->width = bounds->width;
+       if (rect->height > bounds->height)
+               rect->height = bounds->height;
+       if (rect->left < bounds->left)
+               rect->left = bounds->left;
+       if (rect->top < bounds->top)
+               rect->top = bounds->top;
+       if (rect->left + rect->width > bounds->left + bounds->width)
+               rect->left = bounds->left+bounds->width - rect->width;
+       if (rect->top + rect->height > bounds->top + bounds->height)
+               rect->top = bounds->top+bounds->height - rect->height;
+
+       rect->width &= ~3L;
+       rect->height &= ~3L;
+
+       if (ET61X251_PRESERVE_IMGSCALE) {
+               /* Calculate the actual scaling factor */
+               u32 a, b;
+               a = rect->width * rect->height;
+               b = pix_format->width * pix_format->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
+       } else
+               scale = 1;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &crop, sizeof(crop))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               et61x251_release_buffers(cam);
+
+       err = et61x251_set_crop(cam, rect);
+       if (s->set_crop)
+               err += s->set_crop(cam, rect);
+       err += et61x251_set_scale(cam, scale);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       s->pix_format.width = rect->width/scale;
+       s->pix_format.height = rect->height/scale;
+       memcpy(&(s->_rect), rect, sizeof(*rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               et61x251_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               et61x251_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_fmtdesc fmtd;
+
+       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+               return -EFAULT;
+
+       if (fmtd.index == 0) {
+               strcpy(fmtd.description, "bayer rgb");
+               fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
+       } else if (fmtd.index == 1) {
+               strcpy(fmtd.description, "compressed");
+               fmtd.pixelformat = V4L2_PIX_FMT_ET61X251;
+               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+       } else
+               return -EINVAL;
+
+       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+
+       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_format format;
+       struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
+                            ? 0 : (pfmt->width * pfmt->priv) / 8;
+       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+       pfmt->field = V4L2_FIELD_NONE;
+       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+
+       if (copy_to_user(arg, &format, sizeof(format)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
+                          void __user * arg)
+{
+       struct et61x251_sensor* s = cam->sensor;
+       struct v4l2_format format;
+       struct v4l2_pix_format* pix;
+       struct v4l2_pix_format* pfmt = &(s->pix_format);
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_rect rect;
+       u8 scale;
+       const enum et61x251_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       pix = &(format.fmt.pix);
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memcpy(&rect, &(s->_rect), sizeof(rect));
+
+       { /* calculate the actual scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
+       }
+
+       rect.width = scale * pix->width;
+       rect.height = scale * pix->height;
+
+       if (rect.width < 4)
+               rect.width = 4;
+       if (rect.height < 4)
+               rect.height = 4;
+       if (rect.width > bounds->left + bounds->width - rect.left)
+               rect.width = bounds->left + bounds->width - rect.left;
+       if (rect.height > bounds->top + bounds->height - rect.top)
+               rect.height = bounds->top + bounds->height - rect.top;
+
+       rect.width &= ~3L;
+       rect.height &= ~3L;
+
+       { /* adjust the scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
+       }
+
+       pix->width = rect.width / scale;
+       pix->height = rect.height / scale;
+
+       if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 &&
+           pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+               pix->pixelformat = pfmt->pixelformat;
+       pix->priv = pfmt->priv; /* bpp */
+       pix->colorspace = pfmt->colorspace;
+       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
+                           ? 0 : (pix->width * pix->priv) / 8;
+       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+       pix->field = V4L2_FIELD_NONE;
+
+       if (cmd == VIDIOC_TRY_FMT) {
+               if (copy_to_user(arg, &format, sizeof(format)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_FMT failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &format, sizeof(format))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               et61x251_release_buffers(cam);
+
+       err += et61x251_set_pix_format(cam, pix);
+       err += et61x251_set_crop(cam, &rect);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, pix);
+       if (s->set_crop)
+               err += s->set_crop(cam, &rect);
+       err += et61x251_set_scale(cam, scale);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       memcpy(pfmt, pix, sizeof(*pix));
+       memcpy(&(s->_rect), &rect, sizeof(rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               et61x251_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               et61x251_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg)
+{
+       if (copy_to_user(arg, &cam->compression,
+                        sizeof(cam->compression)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_jpegcompression jc;
+       const enum et61x251_stream_state stream = cam->stream;
+       int err = 0;
+
+       if (copy_from_user(&jc, arg, sizeof(jc)))
+               return -EFAULT;
+
+       if (jc.quality != 0 && jc.quality != 1)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       err += et61x251_set_compression(cam, &jc);
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+                      "problems. To use the camera, close and open "
+                      "/dev/video%d again.", cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       cam->compression.quality = jc.quality;
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_requestbuffers rb;
+       u32 i;
+       int err;
+
+       if (copy_from_user(&rb, arg, sizeof(rb)))
+               return -EFAULT;
+
+       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           rb.memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       if (cam->io == IO_READ) {
+               DBG(3, "Close and open the device again to choose the mmap "
+                      "I/O method");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].vma_use_count) {
+                       DBG(3, "VIDIOC_REQBUFS failed. "
+                              "Previous buffers are still mapped.");
+                       return -EINVAL;
+               }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       et61x251_empty_framequeues(cam);
+
+       et61x251_release_buffers(cam);
+       if (rb.count)
+               rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP);
+
+       if (copy_to_user(arg, &rb, sizeof(rb))) {
+               et61x251_release_buffers(cam);
+               cam->io = IO_NONE;
+               return -EFAULT;
+       }
+
+       cam->io = rb.count ? IO_MMAP : IO_NONE;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+
+       if (cam->frame[b.index].vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (cam->frame[b.index].state == F_DONE)
+               b.flags |= V4L2_BUF_FLAG_DONE;
+       else if (cam->frame[b.index].state != F_UNUSED)
+               b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+       unsigned long lock_flags;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->frame[b.index].state != F_UNUSED)
+               return -EINVAL;
+
+       cam->frame[b.index].state = F_QUEUED;
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       PDBGG("Frame #%lu queued", (unsigned long)b.index);
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
+                      void __user * arg)
+{
+       struct v4l2_buffer b;
+       struct et61x251_frame_t *f;
+       unsigned long lock_flags;
+       int err = 0;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->outqueue)) {
+               if (cam->stream == STREAM_OFF)
+                       return -EINVAL;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               err = wait_event_interruptible
+                     ( cam->wait_frame,
+                       (!list_empty(&cam->outqueue)) ||
+                       (cam->state & DEV_DISCONNECTED) ||
+                       (cam->state & DEV_MISCONFIGURED) );
+               if (err)
+                       return err;
+               if (cam->state & DEV_DISCONNECTED)
+                       return -ENODEV;
+               if (cam->state & DEV_MISCONFIGURED)
+                       return -EIO;
+       }
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame);
+       list_del(cam->outqueue.next);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       f->state = F_UNUSED;
+
+       memcpy(&b, &f->buf, sizeof(b));
+       if (f->vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
+{
+       int type;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->inqueue))
+               return -EINVAL;
+
+       cam->stream = STREAM_ON;
+
+       DBG(3, "Stream on");
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg)
+{
+       int type, err;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       et61x251_empty_framequeues(cam);
+
+       DBG(3, "Stream off");
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+       sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+
+       if (sp.parm.capture.readbuffers == 0)
+               sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES)
+               sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+       return 0;
+}
+
+
+static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
+                               unsigned int cmd, void __user * arg)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
+
+       case VIDIOC_QUERYCAP:
+               return et61x251_vidioc_querycap(cam, arg);
+
+       case VIDIOC_ENUMINPUT:
+               return et61x251_vidioc_enuminput(cam, arg);
+
+       case VIDIOC_G_INPUT:
+       case VIDIOC_S_INPUT:
+               return et61x251_vidioc_gs_input(cam, arg);
+
+       case VIDIOC_QUERYCTRL:
+               return et61x251_vidioc_query_ctrl(cam, arg);
+
+       case VIDIOC_G_CTRL:
+               return et61x251_vidioc_g_ctrl(cam, arg);
+
+       case VIDIOC_S_CTRL_OLD:
+       case VIDIOC_S_CTRL:
+               return et61x251_vidioc_s_ctrl(cam, arg);
+
+       case VIDIOC_CROPCAP_OLD:
+       case VIDIOC_CROPCAP:
+               return et61x251_vidioc_cropcap(cam, arg);
+
+       case VIDIOC_G_CROP:
+               return et61x251_vidioc_g_crop(cam, arg);
+
+       case VIDIOC_S_CROP:
+               return et61x251_vidioc_s_crop(cam, arg);
+
+       case VIDIOC_ENUM_FMT:
+               return et61x251_vidioc_enum_fmt(cam, arg);
+
+       case VIDIOC_G_FMT:
+               return et61x251_vidioc_g_fmt(cam, arg);
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+               return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
+
+       case VIDIOC_G_JPEGCOMP:
+               return et61x251_vidioc_g_jpegcomp(cam, arg);
+
+       case VIDIOC_S_JPEGCOMP:
+               return et61x251_vidioc_s_jpegcomp(cam, arg);
+
+       case VIDIOC_REQBUFS:
+               return et61x251_vidioc_reqbufs(cam, arg);
+
+       case VIDIOC_QUERYBUF:
+               return et61x251_vidioc_querybuf(cam, arg);
+
+       case VIDIOC_QBUF:
+               return et61x251_vidioc_qbuf(cam, arg);
+
+       case VIDIOC_DQBUF:
+               return et61x251_vidioc_dqbuf(cam, filp, arg);
+
+       case VIDIOC_STREAMON:
+               return et61x251_vidioc_streamon(cam, arg);
+
+       case VIDIOC_STREAMOFF:
+               return et61x251_vidioc_streamoff(cam, arg);
+
+       case VIDIOC_G_PARM:
+               return et61x251_vidioc_g_parm(cam, arg);
+
+       case VIDIOC_S_PARM_OLD:
+       case VIDIOC_S_PARM:
+               return et61x251_vidioc_s_parm(cam, arg);
+
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_QUERYSTD:
+       case VIDIOC_ENUMSTD:
+       case VIDIOC_QUERYMENU:
+               return -EINVAL;
+
+       default:
+               return -EINVAL;
+
+       }
+}
+
+
+static int et61x251_ioctl(struct inode* inode, struct file* filp,
+                         unsigned int cmd, unsigned long arg)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       int err = 0;
+
+       if (down_interruptible(&cam->fileop_sem))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               up(&cam->fileop_sem);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               up(&cam->fileop_sem);
+               return -EIO;
+       }
+
+       V4LDBG(3, "et61x251", cmd);
+
+       err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+
+       up(&cam->fileop_sem);
+
+       return err;
+}
+
+
+static struct file_operations et61x251_fops = {
+       .owner = THIS_MODULE,
+       .open =    et61x251_open,
+       .release = et61x251_release,
+       .ioctl =   et61x251_ioctl,
+       .read =    et61x251_read,
+       .poll =    et61x251_poll,
+       .mmap =    et61x251_mmap,
+       .llseek =  no_llseek,
+};
+
+/*****************************************************************************/
+
+/* It exists a single interface only. We do not need to validate anything. */
+static int
+et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct et61x251_device* cam;
+       static unsigned int dev_nr = 0;
+       unsigned int i;
+       int err = 0;
+
+       if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL)))
+               return -ENOMEM;
+
+       cam->usbdev = udev;
+
+       if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
+               DBG(1, "kmalloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       if (!(cam->v4ldev = video_device_alloc())) {
+               DBG(1, "video_device_alloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       init_MUTEX(&cam->dev_sem);
+
+       DBG(2, "ET61X[12]51 PC Camera Controller detected "
+              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+
+       for  (i = 0; et61x251_sensor_table[i]; i++) {
+               err = et61x251_sensor_table[i](cam);
+               if (!err)
+                       break;
+       }
+
+       if (!err && cam->sensor)
+               DBG(2, "%s image sensor detected", cam->sensor->name);
+       else {
+               DBG(1, "No supported image sensor detected");
+               err = -ENODEV;
+               goto fail;
+       }
+
+       if (et61x251_init(cam)) {
+               DBG(1, "Initialization failed. I will retry on open().");
+               cam->state |= DEV_MISCONFIGURED;
+       }
+
+       strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera");
+       cam->v4ldev->owner = THIS_MODULE;
+       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+       cam->v4ldev->hardware = 0;
+       cam->v4ldev->fops = &et61x251_fops;
+       cam->v4ldev->minor = video_nr[dev_nr];
+       cam->v4ldev->release = video_device_release;
+       video_set_drvdata(cam->v4ldev, cam);
+
+       down(&cam->dev_sem);
+
+       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+                                   video_nr[dev_nr]);
+       if (err) {
+               DBG(1, "V4L2 device registration failed");
+               if (err == -ENFILE && video_nr[dev_nr] == -1)
+                       DBG(1, "Free /dev/videoX node not found");
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               up(&cam->dev_sem);
+               goto fail;
+       }
+
+       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+
+       cam->module_param.force_munmap = force_munmap[dev_nr];
+
+       dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       et61x251_create_sysfs(cam);
+       DBG(2, "Optional device control through 'sysfs' interface ready");
+#endif
+
+       usb_set_intfdata(intf, cam);
+
+       up(&cam->dev_sem);
+
+       return 0;
+
+fail:
+       if (cam) {
+               kfree(cam->control_buffer);
+               if (cam->v4ldev)
+                       video_device_release(cam->v4ldev);
+               kfree(cam);
+       }
+       return err;
+}
+
+
+static void et61x251_usb_disconnect(struct usb_interface* intf)
+{
+       struct et61x251_device* cam = usb_get_intfdata(intf);
+
+       if (!cam)
+               return;
+
+       down_write(&et61x251_disconnect);
+
+       down(&cam->dev_sem);
+
+       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
+
+       wake_up_interruptible_all(&cam->open);
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is open! Deregistration and "
+                      "memory deallocation are deferred on close.",
+                   cam->v4ldev->minor);
+               cam->state |= DEV_MISCONFIGURED;
+               et61x251_stop_transfer(cam);
+               cam->state |= DEV_DISCONNECTED;
+               wake_up_interruptible(&cam->wait_frame);
+               wake_up_interruptible(&cam->wait_stream);
+       } else {
+               cam->state |= DEV_DISCONNECTED;
+               et61x251_release_resources(cam);
+       }
+
+       up(&cam->dev_sem);
+
+       if (!cam->users)
+               kfree(cam);
+
+       up_write(&et61x251_disconnect);
+}
+
+
+static struct usb_driver et61x251_usb_driver = {
+       .name =       "et61x251",
+       .id_table =   et61x251_id_table,
+       .probe =      et61x251_usb_probe,
+       .disconnect = et61x251_usb_disconnect,
+};
+
+/*****************************************************************************/
+
+static int __init et61x251_module_init(void)
+{
+       int err = 0;
+
+       KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION);
+       KDBG(3, ET61X251_MODULE_AUTHOR);
+
+       if ((err = usb_register(&et61x251_usb_driver)))
+               KDBG(1, "usb_register() failed");
+
+       return err;
+}
+
+
+static void __exit et61x251_module_exit(void)
+{
+       usb_deregister(&et61x251_usb_driver);
+}
+
+
+module_init(et61x251_module_init);
+module_exit(et61x251_module_exit);
diff --git a/drivers/usb/media/et61x251_sensor.h b/drivers/usb/media/et61x251_sensor.h
new file mode 100644 (file)
index 0000000..b9df910
--- /dev/null
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * API for image sensors connected to ET61X[12]51 PC Camera Controllers    *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * 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.               *
+ ***************************************************************************/
+
+#ifndef _ET61X251_SENSOR_H_
+#define _ET61X251_SENSOR_H_
+
+#include <linux/usb.h>
+#include <linux/videodev.h>
+#include <linux/device.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <asm/types.h>
+
+struct et61x251_device;
+struct et61x251_sensor;
+
+/*****************************************************************************/
+
+extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam);
+
+#define ET61X251_SENSOR_TABLE                                                 \
+/* Weak detections must go at the end of the list */                          \
+static int (*et61x251_sensor_table[])(struct et61x251_device*) = {            \
+       &et61x251_probe_tas5130d1b,                                           \
+       NULL,                                                                 \
+};
+
+extern void
+et61x251_attach_sensor(struct et61x251_device* cam,
+                       struct et61x251_sensor* sensor);
+
+/*****************************************************************************/
+
+extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
+extern int et61x251_read_reg(struct et61x251_device*, u16 index);
+extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
+extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
+extern int et61x251_i2c_try_write(struct et61x251_device*,
+                                  struct et61x251_sensor*, u8 address,
+                                  u8 value);
+extern int et61x251_i2c_try_read(struct et61x251_device*,
+                                 struct et61x251_sensor*, u8 address);
+extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
+                                  u8 data2, u8 data3, u8 data4, u8 data5,
+                                  u8 data6, u8 data7, u8 data8, u8 address);
+
+/*****************************************************************************/
+
+enum et61x251_i2c_sysfs_ops {
+       ET61X251_I2C_READ = 0x01,
+       ET61X251_I2C_WRITE = 0x02,
+};
+
+enum et61x251_i2c_interface {
+       ET61X251_I2C_2WIRES,
+       ET61X251_I2C_3WIRES,
+};
+
+/* Repeat start condition when RSTA is high */
+enum et61x251_i2c_rsta {
+       ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */
+       ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
+};
+
+#define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+
+struct et61x251_sensor {
+       char name[32];
+
+       enum et61x251_i2c_sysfs_ops sysfs_ops;
+
+       enum et61x251_i2c_interface interface;
+       u8 i2c_slave_id;
+       enum et61x251_i2c_rsta rsta;
+       struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */
+
+       struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS];
+       struct v4l2_cropcap cropcap;
+       struct v4l2_pix_format pix_format;
+
+       int (*init)(struct et61x251_device* cam);
+       int (*get_ctrl)(struct et61x251_device* cam,
+                       struct v4l2_control* ctrl);
+       int (*set_ctrl)(struct et61x251_device* cam,
+                       const struct v4l2_control* ctrl);
+       int (*set_crop)(struct et61x251_device* cam,
+                       const struct v4l2_rect* rect);
+       int (*set_pix_format)(struct et61x251_device* cam,
+                             const struct v4l2_pix_format* pix);
+
+       const struct usb_device* usbdev;
+
+       /* Private */
+       struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
+       struct v4l2_rect _rect;
+};
+
+#endif /* _ET61X251_SENSOR_H_ */
diff --git a/drivers/usb/media/et61x251_tas5130d1b.c b/drivers/usb/media/et61x251_tas5130d1b.c
new file mode 100644 (file)
index 0000000..65f1ae9
--- /dev/null
@@ -0,0 +1,137 @@
+/***************************************************************************
+ * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51        *
+ * PC Camera Controllers                                                   *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * 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.               *
+ ***************************************************************************/
+
+#include "et61x251_sensor.h"
+
+
+static int tas5130d1b_init(struct et61x251_device* cam)
+{
+       int err = 0;
+
+       err += et61x251_write_reg(cam, 0x14, 0x01);
+       err += et61x251_write_reg(cam, 0x1b, 0x02);
+       err += et61x251_write_reg(cam, 0x02, 0x12);
+       err += et61x251_write_reg(cam, 0x0e, 0x60);
+       err += et61x251_write_reg(cam, 0x80, 0x61);
+       err += et61x251_write_reg(cam, 0xf0, 0x62);
+       err += et61x251_write_reg(cam, 0x03, 0x63);
+       err += et61x251_write_reg(cam, 0x14, 0x64);
+       err += et61x251_write_reg(cam, 0xf4, 0x65);
+       err += et61x251_write_reg(cam, 0x01, 0x66);
+       err += et61x251_write_reg(cam, 0x05, 0x67);
+       err += et61x251_write_reg(cam, 0x8f, 0x68);
+       err += et61x251_write_reg(cam, 0x0f, 0x8d);
+       err += et61x251_write_reg(cam, 0x08, 0x8e);
+
+       return err;
+}
+
+
+static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
+                               const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               err += et61x251_i2c_raw_write(cam, 2, 0x20,
+                                             0xf6-ctrl->value, 0, 0, 0,
+                                             0, 0, 0, 0);
+               break;
+       case V4L2_CID_EXPOSURE:
+               err += et61x251_i2c_raw_write(cam, 2, 0x40,
+                                             0x47-ctrl->value, 0, 0, 0,
+                                             0, 0, 0, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static struct et61x251_sensor tas5130d1b = {
+       .name = "TAS5130D1B",
+       .interface = ET61X251_I2C_3WIRES,
+       .rsta = ET61X251_I2C_RSTA_STOP,
+       .active_pixel = {
+               .left = 106,
+               .top = 13,
+       },
+       .init = &tas5130d1b_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0xf6,
+                       .step = 0x02,
+                       .default_value = 0x0d,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x00,
+                       .maximum = 0x47,
+                       .step = 0x01,
+                       .default_value = 0x23,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &tas5130d1b_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+};
+
+
+int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
+{
+       /* This sensor has no identifiers, so let's attach it anyway */
+       et61x251_attach_sensor(cam, &tas5130d1b);
+
+       /* Sensor detection is based on USB pid/vid */
+       if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6251)
+               return -ENODEV;
+
+       return 0;
+}
index 8af665bbe330b40478b7d2588a263ccc8849f739..51e9cc06f7e313ebeda40572114d527399afb5bc 100644 (file)
@@ -204,22 +204,10 @@ MODULE_LICENSE("GPL");
 
 static struct usb_driver ov511_driver;
 
-static struct ov51x_decomp_ops *ov511_decomp_ops;
-static struct ov51x_decomp_ops *ov511_mmx_decomp_ops;
-static struct ov51x_decomp_ops *ov518_decomp_ops;
-static struct ov51x_decomp_ops *ov518_mmx_decomp_ops;
-
 /* Number of times to retry a failed I2C transaction. Increase this if you
  * are getting "Failed to read sensor ID..." */
 static const int i2c_detect_tries = 5;
 
-/* MMX support is present in kernel and CPU. Checked upon decomp module load. */
-#if defined(__i386__) || defined(__x86_64__)
-#define ov51x_mmx_available (cpu_has_mmx)
-#else
-#define ov51x_mmx_available (0)
-#endif
-
 static struct usb_device_id device_table [] = {
        { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
        { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
@@ -3012,93 +3000,18 @@ yuv420raw_to_yuv420p(struct ov511_frame *frame,
  *
  **********************************************************************/
 
-/* Chooses a decompression module, locks it, and sets ov->decomp_ops
- * accordingly. Returns -ENXIO if decompressor is not available, otherwise
- * returns 0 if no other error.
- */
 static int
 request_decompressor(struct usb_ov511 *ov)
 {
-       if (!ov)
-               return -ENODEV;
-
-       if (ov->decomp_ops) {
-               err("ERROR: Decompressor already requested!");
-               return -EINVAL;
-       }
-
-       lock_kernel();
-
-       /* Try to get MMX, and fall back on no-MMX if necessary */
-       if (ov->bclass == BCL_OV511) {
-               if (ov511_mmx_decomp_ops) {
-                       PDEBUG(3, "Using OV511 MMX decompressor");
-                       ov->decomp_ops = ov511_mmx_decomp_ops;
-               } else if (ov511_decomp_ops) {
-                       PDEBUG(3, "Using OV511 decompressor");
-                       ov->decomp_ops = ov511_decomp_ops;
-               } else {
-                       err("No decompressor available");
-               }
-       } else if (ov->bclass == BCL_OV518) {
-               if (ov518_mmx_decomp_ops) {
-                       PDEBUG(3, "Using OV518 MMX decompressor");
-                       ov->decomp_ops = ov518_mmx_decomp_ops;
-               } else if (ov518_decomp_ops) {
-                       PDEBUG(3, "Using OV518 decompressor");
-                       ov->decomp_ops = ov518_decomp_ops;
-               } else {
-                       err("No decompressor available");
-               }
+       if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) {
+               err("No decompressor available");
        } else {
                err("Unknown bridge");
        }
 
-       if (!ov->decomp_ops)
-               goto nosys;
-
-       if (!ov->decomp_ops->owner) {
-               ov->decomp_ops = NULL;
-               goto nosys;
-       }
-       
-       if (!try_module_get(ov->decomp_ops->owner))
-               goto nosys;
-
-       unlock_kernel();
-       return 0;
-
- nosys:
-       unlock_kernel();
        return -ENOSYS;
 }
 
-/* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even
- * if ov->decomp_ops is NULL.
- */
-static void
-release_decompressor(struct usb_ov511 *ov)
-{
-       int released = 0;       /* Did we actually do anything? */
-
-       if (!ov)
-               return;
-
-       lock_kernel();
-
-       if (ov->decomp_ops) {
-               module_put(ov->decomp_ops->owner);
-               released = 1;
-       }
-
-       ov->decomp_ops = NULL;
-
-       unlock_kernel();
-
-       if (released)
-               PDEBUG(3, "Decompressor released");
-}
-
 static void
 decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
           unsigned char *pIn0, unsigned char *pOut0)
@@ -3107,31 +3020,6 @@ decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
                if (request_decompressor(ov))
                        return;
 
-       PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd);
-
-       if (frame->format == VIDEO_PALETTE_GREY
-           && ov->decomp_ops->decomp_400) {
-               int ret = ov->decomp_ops->decomp_400(
-                       pIn0,
-                       pOut0,
-                       frame->compbuf,
-                       frame->rawwidth,
-                       frame->rawheight,
-                       frame->bytes_recvd);
-               PDEBUG(4, "DEBUG: decomp_400 returned %d", ret);
-       } else if (frame->format != VIDEO_PALETTE_GREY
-                  && ov->decomp_ops->decomp_420) {
-               int ret = ov->decomp_ops->decomp_420(
-                       pIn0,
-                       pOut0,
-                       frame->compbuf,
-                       frame->rawwidth,
-                       frame->rawheight,
-                       frame->bytes_recvd);
-               PDEBUG(4, "DEBUG: decomp_420 returned %d", ret);
-       } else {
-               err("Decompressor does not support this format");
-       }
 }
 
 /**********************************************************************
@@ -4087,8 +3975,6 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
        ov->user--;
        ov51x_stop_isoc(ov);
 
-       release_decompressor(ov);
-
        if (ov->led_policy == LED_AUTO)
                ov51x_led_control(ov, 0);
 
@@ -6021,82 +5907,6 @@ static struct usb_driver ov511_driver = {
  *
  ***************************************************************************/
 
-/* Returns 0 for success */
-int
-ov511_register_decomp_module(int ver, struct ov51x_decomp_ops *ops, int ov518,
-                            int mmx)
-{
-       if (ver != DECOMP_INTERFACE_VER) {
-               err("Decompression module has incompatible");
-               err("interface version %d", ver);
-               err("Interface version %d is required", DECOMP_INTERFACE_VER);
-               return -EINVAL;
-       }
-
-       if (!ops)
-               return -EFAULT;
-
-       if (mmx && !ov51x_mmx_available) {
-               err("MMX not available on this system or kernel");
-               return -EINVAL;
-       }
-
-       lock_kernel();
-
-       if (ov518) {
-               if (mmx) {
-                       if (ov518_mmx_decomp_ops)
-                               goto err_in_use;
-                       else
-                               ov518_mmx_decomp_ops = ops;
-               } else {
-                       if (ov518_decomp_ops)
-                               goto err_in_use;
-                       else
-                               ov518_decomp_ops = ops;
-               }
-       } else {
-               if (mmx) {
-                       if (ov511_mmx_decomp_ops)
-                               goto err_in_use;
-                       else
-                               ov511_mmx_decomp_ops = ops;
-               } else {
-                       if (ov511_decomp_ops)
-                               goto err_in_use;
-                       else
-                               ov511_decomp_ops = ops;
-               }
-       }
-
-       unlock_kernel();
-       return 0;
-
-err_in_use:
-       unlock_kernel();
-       return -EBUSY;
-}
-
-void
-ov511_deregister_decomp_module(int ov518, int mmx)
-{
-       lock_kernel();
-
-       if (ov518) {
-               if (mmx)
-                       ov518_mmx_decomp_ops = NULL;
-               else
-                       ov518_decomp_ops = NULL;
-       } else {
-               if (mmx)
-                       ov511_mmx_decomp_ops = NULL;
-               else
-                       ov511_decomp_ops = NULL;
-       }
-
-       unlock_kernel();
-}
-
 static int __init
 usb_ov511_init(void)
 {
@@ -6123,5 +5933,3 @@ usb_ov511_exit(void)
 module_init(usb_ov511_init);
 module_exit(usb_ov511_exit);
 
-EXPORT_SYMBOL(ov511_register_decomp_module);
-EXPORT_SYMBOL(ov511_deregister_decomp_module);
index 359c4b2df735917ff685920f160a1fa7ee1c7476..3ebb6e9cdf92cee2179fd3d43fc6bbbf3b50b26d 100644 (file)
@@ -1152,45 +1152,6 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
  /* End of Add-Ons                                    */
  /* ************************************************* */
 
-/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
-   ioctl() calls. With 2.4, you have to do tedious copy_from_user()
-   and copy_to_user() calls. With these macros we circumvent this,
-   and let me maintain only one source file. The functionality is
-   exactly the same otherwise.
- */   
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
-
-/* define local variable for arg */
-#define ARG_DEF(ARG_type, ARG_name)\
-       ARG_type *ARG_name = arg;
-/* copy arg to local variable */       
-#define ARG_IN(ARG_name) /* nothing */
-/* argument itself (referenced) */
-#define ARGR(ARG_name) (*ARG_name)
-/* argument address */
-#define ARGA(ARG_name) ARG_name
-/* copy local variable to arg */
-#define ARG_OUT(ARG_name) /* nothing */
-
-#else
-
-#define ARG_DEF(ARG_type, ARG_name)\
-       ARG_type ARG_name;
-#define ARG_IN(ARG_name)\
-       if (copy_from_user(&ARG_name, arg, sizeof(ARG_name))) {\
-               ret = -EFAULT;\
-               break;\
-       }
-#define ARGR(ARG_name) ARG_name
-#define ARGA(ARG_name) &ARG_name
-#define ARG_OUT(ARG_name)\
-       if (copy_to_user(arg, &ARG_name, sizeof(ARG_name))) {\
-               ret = -EFAULT;\
-               break;\
-       }
-
-#endif
 
 int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 {
@@ -1220,243 +1181,206 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        
        case VIDIOCPWCSCQUAL:
        {       
-               ARG_DEF(int, qual)
+               int *qual = arg;
 
-               ARG_IN(qual)
-               if (ARGR(qual) < 0 || ARGR(qual) > 3)
+               if (*qual < 0 || *qual > 3)
                        ret = -EINVAL;
                else
-                       ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
+                       ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
                if (ret >= 0)
-                       pdev->vcompression = ARGR(qual);
+                       pdev->vcompression = *qual;
                break;
        }
        
        case VIDIOCPWCGCQUAL:
        {
-               ARG_DEF(int, qual)
-               
-               ARGR(qual) = pdev->vcompression;
-               ARG_OUT(qual)
+               int *qual = arg;
+               *qual = pdev->vcompression;
                break;
        }
        
        case VIDIOCPWCPROBE:
        {
-               ARG_DEF(struct pwc_probe, probe)
-               
-               strcpy(ARGR(probe).name, pdev->vdev->name);
-               ARGR(probe).type = pdev->type;
-               ARG_OUT(probe)
+               struct pwc_probe *probe = arg;
+               strcpy(probe->name, pdev->vdev->name);
+               probe->type = pdev->type;
                break;
        }
 
        case VIDIOCPWCGSERIAL:
        {
-               ARG_DEF(struct pwc_serial, serial)
-               
-               strcpy(ARGR(serial).serial, pdev->serial);
-               ARG_OUT(serial)
+               struct pwc_serial *serial = arg;
+               strcpy(serial->serial, pdev->serial);
                break;
        }
 
        case VIDIOCPWCSAGC:
        {
-               ARG_DEF(int, agc)
-
-               ARG_IN(agc)
-               if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
+               int *agc = arg;
+               if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
                        ret = -EINVAL;
                break;
        }
        
        case VIDIOCPWCGAGC:
        {
-               ARG_DEF(int, agc)
+               int *agc = arg;
                
-               if (pwc_get_agc(pdev, ARGA(agc)))
+               if (pwc_get_agc(pdev, agc))
                        ret = -EINVAL;
-               ARG_OUT(agc)
                break;
        }
        
        case VIDIOCPWCSSHUTTER:
        {
-               ARG_DEF(int, shutter_speed)
-
-               ARG_IN(shutter_speed)
-               ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
+               int *shutter_speed = arg;
+               ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
                break;
        }
        
         case VIDIOCPWCSAWB:
        {
-               ARG_DEF(struct pwc_whitebalance, wb)
+               struct pwc_whitebalance *wb = arg;
                
-               ARG_IN(wb)
-               ret = pwc_set_awb(pdev, ARGR(wb).mode);
-               if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
-                       pwc_set_red_gain(pdev, ARGR(wb).manual_red);
-                       pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
+               ret = pwc_set_awb(pdev, wb->mode);
+               if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
+                       pwc_set_red_gain(pdev, wb->manual_red);
+                       pwc_set_blue_gain(pdev, wb->manual_blue);
                }
                break;
        }
 
        case VIDIOCPWCGAWB:
        {
-               ARG_DEF(struct pwc_whitebalance, wb)
+               struct pwc_whitebalance *wb = arg;
 
-               memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
-               ARGR(wb).mode = pwc_get_awb(pdev);
-               if (ARGR(wb).mode < 0)
+               memset(wb, 0, sizeof(struct pwc_whitebalance));
+               wb->mode = pwc_get_awb(pdev);
+               if (wb->mode < 0)
                        ret = -EINVAL;
                else {
-                       if (ARGR(wb).mode == PWC_WB_MANUAL) {
-                               ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
+                       if (wb->mode == PWC_WB_MANUAL) {
+                               ret = pwc_get_red_gain(pdev, &wb->manual_red);
                                if (ret < 0)
                                        break;
-                               ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
+                               ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
                                if (ret < 0)
                                        break;
                        }
-                       if (ARGR(wb).mode == PWC_WB_AUTO) {
-                               ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
+                       if (wb->mode == PWC_WB_AUTO) {
+                               ret = pwc_read_red_gain(pdev, &wb->read_red);
                                if (ret < 0)
                                        break;
-                               ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
+                               ret = pwc_read_blue_gain(pdev, &wb->read_blue);
                                if (ret < 0)
                                        break;
                        }
                }
-               ARG_OUT(wb)
                break;
        }
        
        case VIDIOCPWCSAWBSPEED:
        {
-               ARG_DEF(struct pwc_wb_speed, wbs)
+               struct pwc_wb_speed *wbs = arg;
                
-               if (ARGR(wbs).control_speed > 0) {
-                       ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
+               if (wbs->control_speed > 0) {
+                       ret = pwc_set_wb_speed(pdev, wbs->control_speed);
                }
-               if (ARGR(wbs).control_delay > 0) {
-                       ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
+               if (wbs->control_delay > 0) {
+                       ret = pwc_set_wb_delay(pdev, wbs->control_delay);
                }
                break;
        }
        
        case VIDIOCPWCGAWBSPEED:
        {
-               ARG_DEF(struct pwc_wb_speed, wbs)
+               struct pwc_wb_speed *wbs = arg;
                
-               ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
+               ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
                if (ret < 0)
                        break;
-               ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
+               ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
                if (ret < 0)
                        break;
-               ARG_OUT(wbs)
                break;
        }
 
         case VIDIOCPWCSLED:
        {
-               ARG_DEF(struct pwc_leds, leds)
-
-               ARG_IN(leds)
-               ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
+               struct pwc_leds *leds = arg;
+               ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
                break;
        }
 
 
        case VIDIOCPWCGLED:
        {
-               ARG_DEF(struct pwc_leds, leds)
-               
-               ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
-               ARG_OUT(leds)
+               struct pwc_leds *leds = arg;
+               ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
                break;
        }
 
        case VIDIOCPWCSCONTOUR:
        {
-               ARG_DEF(int, contour)
-
-               ARG_IN(contour)
-               ret = pwc_set_contour(pdev, ARGR(contour));
+               int *contour = arg;
+               ret = pwc_set_contour(pdev, *contour);
                break;
        }
                        
        case VIDIOCPWCGCONTOUR:
        {
-               ARG_DEF(int, contour)
-               
-               ret = pwc_get_contour(pdev, ARGA(contour));
-               ARG_OUT(contour)
+               int *contour = arg;
+               ret = pwc_get_contour(pdev, contour);
                break;
        }
        
        case VIDIOCPWCSBACKLIGHT:
        {
-               ARG_DEF(int, backlight)
-               
-               ARG_IN(backlight)
-               ret = pwc_set_backlight(pdev, ARGR(backlight));
+               int *backlight = arg;
+               ret = pwc_set_backlight(pdev, *backlight);
                break;
        }
 
        case VIDIOCPWCGBACKLIGHT:
        {
-               ARG_DEF(int, backlight)
-               
-               ret = pwc_get_backlight(pdev, ARGA(backlight));
-               ARG_OUT(backlight)
+               int *backlight = arg;
+               ret = pwc_get_backlight(pdev, backlight);
                break;
        }
        
        case VIDIOCPWCSFLICKER:
        {
-               ARG_DEF(int, flicker)
-               
-               ARG_IN(flicker)
-               ret = pwc_set_flicker(pdev, ARGR(flicker));
+               int *flicker = arg;
+               ret = pwc_set_flicker(pdev, *flicker);
                break;
        }
 
        case VIDIOCPWCGFLICKER:
        {
-               ARG_DEF(int, flicker)
-               
-               ret = pwc_get_flicker(pdev, ARGA(flicker));
-               ARG_OUT(flicker)
+               int *flicker = arg;
+               ret = pwc_get_flicker(pdev, flicker);
                break;
        }
        
        case VIDIOCPWCSDYNNOISE:
        {
-               ARG_DEF(int, dynnoise)
-               
-               ARG_IN(dynnoise)
-               ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
+               int *dynnoise = arg;
+               ret = pwc_set_dynamic_noise(pdev, *dynnoise);
                break;
        }
        
        case VIDIOCPWCGDYNNOISE:
        {
-               ARG_DEF(int, dynnoise)
-
-               ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
-               ARG_OUT(dynnoise);
+               int *dynnoise = arg;
+               ret = pwc_get_dynamic_noise(pdev, dynnoise);
                break;
        }
 
        case VIDIOCPWCGREALSIZE:
        {
-               ARG_DEF(struct pwc_imagesize, size)
-               
-               ARGR(size).width = pdev->image.x;
-               ARGR(size).height = pdev->image.y;
-               ARG_OUT(size)
+               struct pwc_imagesize *size = arg;
+               size->width = pdev->image.x;
+               size->height = pdev->image.y;
                break;
        }
        
@@ -1464,10 +1388,9 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        {
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       ARG_DEF(int, flags)
+                       int *flags = arg;
 
-                       ARG_IN(flags)
-                       ret = pwc_mpt_reset(pdev, ARGR(flags));
+                       ret = pwc_mpt_reset(pdev, *flags);
                        if (ret >= 0)
                        {
                                pdev->pan_angle = 0;
@@ -1485,10 +1408,8 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        {
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       ARG_DEF(struct pwc_mpt_range, range)
-                       
-                       ARGR(range) = pdev->angle_range;
-                       ARG_OUT(range)
+                       struct pwc_mpt_range *range = arg;
+                       *range = pdev->angle_range;
                }
                else
                {       
@@ -1503,21 +1424,19 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
                
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       ARG_DEF(struct pwc_mpt_angles, angles)
-
-                       ARG_IN(angles)
+                       struct pwc_mpt_angles *angles = arg;
                        /* The camera can only set relative angles, so
                           do some calculations when getting an absolute angle .
                         */
-                       if (ARGR(angles).absolute)
+                       if (angles->absolute)
                        {
-                               new_pan  = ARGR(angles).pan; 
-                               new_tilt = ARGR(angles).tilt;
+                               new_pan  = angles->pan;
+                               new_tilt = angles->tilt;
                        }
                        else
                        {
-                               new_pan  = pdev->pan_angle  + ARGR(angles).pan;
-                               new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
+                               new_pan  = pdev->pan_angle  + angles->pan;
+                               new_tilt = pdev->tilt_angle + angles->tilt;
                        }
                        /* check absolute ranges */
                        if (new_pan  < pdev->angle_range.pan_min  ||
@@ -1560,12 +1479,11 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
                
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       ARG_DEF(struct pwc_mpt_angles, angles)
+                       struct pwc_mpt_angles *angles = arg;
 
-                       ARGR(angles).absolute = 1;
-                       ARGR(angles).pan  = pdev->pan_angle;
-                       ARGR(angles).tilt = pdev->tilt_angle;
-                       ARG_OUT(angles)
+                       angles->absolute = 1;
+                       angles->pan  = pdev->pan_angle;
+                       angles->tilt = pdev->tilt_angle;
                }
                else
                {
@@ -1578,10 +1496,8 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        {
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       ARG_DEF(struct pwc_mpt_status, status)
-                       
-                       ret = pwc_mpt_get_status(pdev, ARGA(status));
-                       ARG_OUT(status)
+                       struct pwc_mpt_status *status = arg;
+                       ret = pwc_mpt_get_status(pdev, status);
                }
                else
                {
@@ -1592,24 +1508,22 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 
        case VIDIOCPWCGVIDCMD:
        {
-               ARG_DEF(struct pwc_video_command, cmd);
+               struct pwc_video_command *cmd = arg;
                
-                ARGR(cmd).type = pdev->type;
-               ARGR(cmd).release = pdev->release;
-               ARGR(cmd).command_len = pdev->cmd_len;
-               memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
-               ARGR(cmd).bandlength = pdev->vbandlength;
-               ARGR(cmd).frame_size = pdev->frame_size;
-               ARG_OUT(cmd)
+                cmd->type = pdev->type;
+               cmd->release = pdev->release;
+               cmd->command_len = pdev->cmd_len;
+               memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
+               cmd->bandlength = pdev->vbandlength;
+               cmd->frame_size = pdev->frame_size;
                break;
        }
        /*
        case VIDIOCPWCGVIDTABLE:
        {
-               ARG_DEF(struct pwc_table_init_buffer, table);
-               ARGR(table).len = pdev->cmd_len;
-               memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
-               ARG_OUT(table)
+               struct pwc_table_init_buffer *table = arg;
+               table->len = pdev->cmd_len;
+               memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
                break;
        }
        */
index e5cea0e2eb5700195d24e858a66404048af9653f..17d60c1eea7eb6e9713b59b20aadf2712d03014a 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************************
  * V4L2 driver for SN9C10x PC Camera Controllers                           *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
@@ -23,7 +23,8 @@
 
 #include <linux/version.h>
 #include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
 #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
 /*****************************************************************************/
 
-#define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
-#define SN9C102_MODULE_AUTHOR   "(C) 2004-2005 Luca Risolia"
-#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
-#define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.24a"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 24)
-
 enum sn9c102_bridge {
        BRIDGE_SN9C101 = 0x01,
        BRIDGE_SN9C102 = 0x02,
@@ -102,12 +96,13 @@ enum sn9c102_stream_state {
        STREAM_ON,
 };
 
+typedef char sn9c103_sof_header_t[18];
 typedef char sn9c102_sof_header_t[12];
 typedef char sn9c102_eof_header_t[4];
 
 struct sn9c102_sysfs_attr {
        u8 reg, i2c_reg;
-       sn9c102_sof_header_t frame_header;
+       sn9c103_sof_header_t frame_header;
 };
 
 struct sn9c102_module_param {
@@ -118,8 +113,6 @@ static DECLARE_MUTEX(sn9c102_sysfs_lock);
 static DECLARE_RWSEM(sn9c102_disconnect);
 
 struct sn9c102_device {
-       struct device dev;
-
        struct video_device* v4ldev;
 
        enum sn9c102_bridge bridge;
@@ -140,8 +133,8 @@ struct sn9c102_device {
        struct v4l2_jpegcompression compression;
 
        struct sn9c102_sysfs_attr sysfs;
-       sn9c102_sof_header_t sof_header;
-       u16 reg[32];
+       sn9c103_sof_header_t sof_header;
+       u16 reg[63];
 
        struct sn9c102_module_param module_param;
 
@@ -160,7 +153,6 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
                       struct sn9c102_sensor* sensor)
 {
        cam->sensor = sensor;
-       cam->sensor->dev = &cam->dev;
        cam->sensor->usbdev = cam->usbdev;
 }
 
@@ -170,19 +162,24 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
 #undef KDBG
 #ifdef SN9C102_DEBUG
 #      define DBG(level, fmt, args...)                                       \
-{                                                                             \
+do {                                                                          \
        if (debug >= (level)) {                                               \
                if ((level) == 1)                                             \
-                       dev_err(&cam->dev, fmt "\n", ## args);                \
+                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
                else if ((level) == 2)                                        \
-                       dev_info(&cam->dev, fmt "\n", ## args);               \
+                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
                else if ((level) >= 3)                                        \
-                       dev_info(&cam->dev, "[%s:%d] " fmt "\n",              \
+                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
                                 __FUNCTION__, __LINE__ , ## args);           \
        }                                                                     \
-}
+} while (0)
+#      define V4LDBG(level, name, cmd)                                       \
+do {                                                                          \
+       if (debug >= (level))                                                 \
+               v4l_print_ioctl(name, cmd);                                   \
+} while (0)
 #      define KDBG(level, fmt, args...)                                      \
-{                                                                             \
+do {                                                                          \
        if (debug >= (level)) {                                               \
                if ((level) == 1 || (level) == 2)                             \
                        pr_info("sn9c102: " fmt "\n", ## args);               \
@@ -190,17 +187,18 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
                        pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__,  \
                                 __LINE__ , ## args);                         \
        }                                                                     \
-}
+} while (0)
 #else
-#      define KDBG(level, fmt, args...) do {;} while(0);
-#      define DBG(level, fmt, args...) do {;} while(0);
+#      define DBG(level, fmt, args...) do {;} while(0)
+#      define V4LDBG(level, name, cmd) do {;} while(0)
+#      define KDBG(level, fmt, args...) do {;} while(0)
 #endif
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
+dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
 
 #undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0); /* placeholder */
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
 
 #endif /* _SN9C102_H_ */
index 8d1a1c357d5a6d7c01b39fc7b53036a5780f218a..c81397e4714ba42791c11dc9642e1b9634106dea 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************************
  * V4L2 driver for SN9C10x PC Camera Controllers                           *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
 
 /*****************************************************************************/
 
+#define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
+#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
+#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
+#define SN9C102_MODULE_LICENSE  "GPL"
+#define SN9C102_MODULE_VERSION  "1:1.26"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 26)
+
+/*****************************************************************************/
+
 MODULE_DEVICE_TABLE(usb, sn9c102_id_table);
 
 MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
@@ -70,10 +79,10 @@ static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
                                SN9C102_FORCE_MUNMAP};
 module_param_array(force_munmap, bool, NULL, 0444);
 MODULE_PARM_DESC(force_munmap,
-                 "\n<0|1[,...]> Force the application to unmap previously "
-                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or "
-                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support "
-                 "\nthis feature. This parameter is specific for each "
+                 "\n<0|1[,...]> Force the application to unmap previously"
+                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                 "\nthis feature. This parameter is specific for each"
                  "\ndetected camera."
                  "\n 0 = do not force memory unmapping"
                  "\n 1 = force memory unmapping (save memory)"
@@ -102,6 +111,9 @@ static sn9c102_sof_header_t sn9c102_sof_header[] = {
        {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
 };
 
+static sn9c103_sof_header_t sn9c103_sof_header[] = {
+       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
+};
 
 static sn9c102_eof_header_t sn9c102_eof_header[] = {
        {0x00, 0x00, 0x00, 0x00},
@@ -112,50 +124,6 @@ static sn9c102_eof_header_t sn9c102_eof_header[] = {
 
 /*****************************************************************************/
 
-static void* rvmalloc(size_t size)
-{
-       void* mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-
-       mem = vmalloc_32((unsigned long)size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size);
-
-       adr = (unsigned long)mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-
-static void rvfree(void* mem, size_t size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       size = PAGE_ALIGN(size);
-
-       adr = (unsigned long)mem;
-       while (size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       vfree(mem);
-}
-
-
 static u32 
 sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, 
                         enum sn9c102_io_method io)
@@ -174,7 +142,7 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
 
        cam->nbuffers = count;
        while (cam->nbuffers > 0) {
-               if ((buff = rvmalloc(cam->nbuffers * PAGE_ALIGN(imagesize))))
+               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
                        break;
                cam->nbuffers--;
        }
@@ -198,10 +166,10 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
 static void sn9c102_release_buffers(struct sn9c102_device* cam)
 {
        if (cam->nbuffers) {
-               rvfree(cam->frame[0].bufmem,
-                      cam->nbuffers * PAGE_ALIGN(cam->frame[0].buf.length));
+               vfree(cam->frame[0].bufmem);
                cam->nbuffers = 0;
        }
+       cam->frame_current = NULL;
 }
 
 
@@ -219,6 +187,19 @@ static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
 }
 
 
+static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
+{
+       struct sn9c102_frame_t *i;
+
+       list_for_each_entry(i, &cam->outqueue, frame) {
+               i->state = F_QUEUED;
+               list_add(&i->frame, &cam->inqueue);
+       }
+
+       INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
 static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
 {
        unsigned long lock_flags;
@@ -235,19 +216,46 @@ static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
 
 /*****************************************************************************/
 
+int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       int i, res;
+
+       if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg))
+               return -1;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             index, 0, buff, sizeof(buff),
+                             SN9C102_CTRL_TIMEOUT*sizeof(buff));
+       if (res < 0) {
+               DBG(3, "Failed to write registers (index 0x%02X, error %d)",
+                   index, res);
+               return -1;
+       }
+
+       for (i = 0; i < sizeof(buff); i++)
+               cam->reg[index+i] = buff[i];
+
+       return 0;
+}
+
+
 int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
 {
        struct usb_device* udev = cam->usbdev;
        u8* buff = cam->control_buffer;
        int res;
 
+       if (index >= ARRAY_SIZE(cam->reg))
+               return -1;
+
        *buff = value;
 
        res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
                              index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
        if (res < 0) {
                DBG(3, "Failed to write a register (value 0x%02X, index "
-                      "0x%02X, error %d)", value, index, res)
+                      "0x%02X, error %d)", value, index, res);
                return -1;
        }
 
@@ -268,7 +276,7 @@ static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
                              index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
        if (res < 0)
                DBG(3, "Failed to read a register (index 0x%02X, error %d)",
-                   index, res)
+                   index, res);
 
        return (res >= 0) ? (int)(*buff) : -1;
 }
@@ -276,8 +284,8 @@ static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
 
 int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
 {
-       if (index > 0x1f)
-               return -EINVAL;
+       if (index >= ARRAY_SIZE(cam->reg))
+               return -1;
 
        return cam->reg[index];
 }
@@ -367,10 +375,10 @@ sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
        err += sn9c102_i2c_detect_read_error(cam, sensor);
 
        PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1,
-             data[4])
+             data[4]);
 
        if (err) {
-               DBG(3, "I2C read failed for %s image sensor", sensor->name)
+               DBG(3, "I2C read failed for %s image sensor", sensor->name);
                return -1;
        }
 
@@ -410,11 +418,11 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
        err += sn9c102_i2c_detect_write_error(cam, sensor);
 
        if (err)
-               DBG(3, "I2C write failed for %s image sensor", sensor->name)
+               DBG(3, "I2C write failed for %s image sensor", sensor->name);
 
        PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
              "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
-             n, data0, data1, data2, data3, data4, data5)
+             n, data0, data1, data2, data3, data4, data5);
 
        return err ? -1 : 0;
 }
@@ -461,13 +469,27 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
 static void*
 sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
 {
-       size_t soflen = sizeof(sn9c102_sof_header_t), i;
-       u8 j, n = sizeof(sn9c102_sof_header) / soflen;
+       size_t soflen = 0, i;
+       u8 j, n = 0;
+
+       switch (cam->bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               soflen = sizeof(sn9c102_sof_header_t);
+               n = sizeof(sn9c102_sof_header) / soflen;
+               break;
+       case BRIDGE_SN9C103:
+               soflen = sizeof(sn9c103_sof_header_t);
+               n = sizeof(sn9c103_sof_header) / soflen;
+       }
 
-       for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
+       for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
                for (j = 0; j < n; j++)
-                       /* It's enough to compare 7 bytes */
-                       if (!memcmp(mem + i, sn9c102_sof_header[j], 7)) {
+                       /* The invariable part of the header is 6 bytes long */
+                       if ((cam->bridge != BRIDGE_SN9C103 &&
+                           !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
+                           (cam->bridge == BRIDGE_SN9C103 &&
+                           !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
                                memcpy(cam->sof_header, mem + i, soflen);
                                /* Skip the header */
                                return mem + i + soflen;
@@ -499,8 +521,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
 {
        struct sn9c102_device* cam = urb->context;
        struct sn9c102_frame_t** f;
-       size_t imagesize;
-       unsigned long lock_flags;
+       size_t imagesize, soflen;
        u8 i;
        int err = 0;
 
@@ -513,7 +534,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
                cam->stream = STREAM_OFF;
                if ((*f))
                        (*f)->state = F_QUEUED;
-               DBG(3, "Stream interrupted")
+               DBG(3, "Stream interrupted");
                wake_up_interruptible(&cam->wait_stream);
        }
 
@@ -536,6 +557,10 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
                     cam->sensor->pix_format.height *
                     cam->sensor->pix_format.priv) / 8;
 
+       soflen = (cam->bridge) == BRIDGE_SN9C103 ?
+                                 sizeof(sn9c103_sof_header_t) :
+                                 sizeof(sn9c102_sof_header_t);
+
        for (i = 0; i < urb->number_of_packets; i++) {
                unsigned int img, len, status;
                void *pos, *sof, *eof;
@@ -545,19 +570,12 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
                pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
 
                if (status) {
-                       DBG(3, "Error in isochronous frame")
+                       DBG(3, "Error in isochronous frame");
                        (*f)->state = F_ERROR;
                        continue;
                }
 
-               PDBGG("Isochrnous frame: length %u, #%u i", len, i)
-
-               /*
-                  NOTE: It is probably correct to assume that SOF and EOF
-                        headers do not occur between two consecutive packets,
-                        but who knows..Whatever is the truth, this assumption
-                        doesn't introduce bugs.
-               */
+               PDBGG("Isochrnous frame: length %u, #%u i", len, i);
 
 redo:
                sof = sn9c102_find_sof_header(cam, pos, len);
@@ -575,10 +593,10 @@ end_of_frame:
                                                imagesize;
                                        img = imagesize - (*f)->buf.bytesused;
                                        DBG(3, "Expected EOF not found: "
-                                              "video frame cut")
+                                              "video frame cut");
                                        if (eof)
                                                DBG(3, "Exceeded limit: +%u "
-                                                      "bytes", (unsigned)(b))
+                                                      "bytes", (unsigned)(b));
                                }
 
                                memcpy((*f)->bufmem + (*f)->buf.bytesused, pos,
@@ -595,8 +613,7 @@ end_of_frame:
                                        u32 b = (*f)->buf.bytesused;
                                        (*f)->state = F_DONE;
                                        (*f)->buf.sequence= ++cam->frame_count;
-                                       spin_lock_irqsave(&cam->queue_lock,
-                                                         lock_flags);
+                                       spin_lock(&cam->queue_lock);
                                        list_move_tail(&(*f)->frame,
                                                       &cam->outqueue);
                                        if (!list_empty(&cam->inqueue))
@@ -606,13 +623,11 @@ end_of_frame:
                                                        frame );
                                        else
                                                (*f) = NULL;
-                                       spin_unlock_irqrestore(&cam->queue_lock
-                                                              , lock_flags);
+                                       spin_unlock(&cam->queue_lock);
                                        memcpy(cam->sysfs.frame_header,
-                                              cam->sof_header,
-                                              sizeof(sn9c102_sof_header_t));
-                                       DBG(3, "Video frame captured: "
-                                              "%lu bytes", (unsigned long)(b))
+                                              cam->sof_header, soflen);
+                                       DBG(3, "Video frame captured: %lu "
+                                              "bytes", (unsigned long)(b));
 
                                        if (!(*f))
                                                goto resubmit_urb;
@@ -621,18 +636,19 @@ end_of_frame:
                                        (*f)->state = F_ERROR;
                                        DBG(3, "Not expected EOF after %lu "
                                               "bytes of image data", 
-                                         (unsigned long)((*f)->buf.bytesused))
+                                           (unsigned long)
+                                           ((*f)->buf.bytesused));
                                }
 
                                if (sof) /* (1) */
                                        goto start_of_frame;
 
                        } else if (eof) {
-                               DBG(3, "EOF without SOF")
+                               DBG(3, "EOF without SOF");
                                continue;
 
                        } else {
-                               PDBGG("Ignoring pointless isochronous frame")
+                               PDBGG("Ignoring pointless isochronous frame");
                                continue;
                        }
 
@@ -642,7 +658,7 @@ start_of_frame:
                        (*f)->buf.bytesused = 0;
                        len -= (sof - pos);
                        pos = sof;
-                       DBG(3, "SOF detected: new video frame")
+                       DBG(3, "SOF detected: new video frame");
                        if (len)
                                goto redo;
 
@@ -653,12 +669,13 @@ start_of_frame:
                        else {
                                if (cam->sensor->pix_format.pixelformat ==
                                    V4L2_PIX_FMT_SN9C10X) {
-                                       eof = sof-sizeof(sn9c102_sof_header_t);
+                                       eof = sof - soflen;
                                        goto end_of_frame;
                                } else {
                                        DBG(3, "SOF before expected EOF after "
                                               "%lu bytes of image data", 
-                                         (unsigned long)((*f)->buf.bytesused))
+                                           (unsigned long)
+                                           ((*f)->buf.bytesused));
                                        goto start_of_frame;
                                }
                        }
@@ -670,7 +687,7 @@ resubmit_urb:
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0 && err != -EPERM) {
                cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "usb_submit_urb() failed")
+               DBG(1, "usb_submit_urb() failed");
        }
 
        wake_up_interruptible(&cam->wait_frame);
@@ -681,18 +698,22 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
 {
        struct usb_device *udev = cam->usbdev;
        struct urb* urb;
-       const unsigned int wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                              680, 800, 900, 1023};
-       const unsigned int psz = wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
+       const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
+                                                      680, 800, 900, 1023};
+       const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
+                                                      680, 800, 900, 1003};
+       const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
+                           sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
+                           sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
        s8 i, j;
        int err = 0;
 
        for (i = 0; i < SN9C102_URBS; i++) {
-               cam->transfer_buffer[i] = kmalloc(SN9C102_ISO_PACKETS * psz,
+               cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz,
                                                  GFP_KERNEL);
                if (!cam->transfer_buffer[i]) {
                        err = -ENOMEM;
-                       DBG(1, "Not enough memory")
+                       DBG(1, "Not enough memory");
                        goto free_buffers;
                }
        }
@@ -702,7 +723,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
                cam->urb[i] = urb;
                if (!urb) {
                        err = -ENOMEM;
-                       DBG(1, "usb_alloc_urb() failed")
+                       DBG(1, "usb_alloc_urb() failed");
                        goto free_urbs;
                }
                urb->dev = udev;
@@ -725,14 +746,14 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
                err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01);
                if (err) {
                        err = -EIO;
-                       DBG(1, "I/O hardware error")
+                       DBG(1, "I/O hardware error");
                        goto free_urbs;
                }
        }
 
        err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING);
        if (err) {
-               DBG(1, "usb_set_interface() failed")
+               DBG(1, "usb_set_interface() failed");
                goto free_urbs;
        }
 
@@ -743,7 +764,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
                if (err) {
                        for (j = i-1; j >= 0; j--)
                                usb_kill_urb(cam->urb[j]);
-                       DBG(1, "usb_submit_urb() failed, error %d", err)
+                       DBG(1, "usb_submit_urb() failed, error %d", err);
                        goto free_urbs;
                }
        }
@@ -779,7 +800,7 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)
 
        err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
        if (err)
-               DBG(3, "usb_set_interface() failed")
+               DBG(3, "usb_set_interface() failed");
 
        return err;
 }
@@ -799,7 +820,7 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
        else if (err) {
                cam->state |= DEV_MISCONFIGURED;
                DBG(1, "The camera is misconfigured. To use it, close and "
-                      "open /dev/video%d again.", cam->v4ldev->minor)
+                      "open /dev/video%d again.", cam->v4ldev->minor);
                return err;
        }
 
@@ -808,6 +829,7 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
 
 /*****************************************************************************/
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
 static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
 {
        char str[5];
@@ -885,8 +907,8 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
 
        cam->sysfs.reg = index;
 
-       DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg)
-       DBG(3, "Written bytes: %zd", count)
+       DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
+       DBG(3, "Written bytes: %zd", count);
 
        up(&sn9c102_sysfs_lock);
 
@@ -916,7 +938,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
 
        count = sprintf(buf, "%d\n", val);
 
-       DBG(3, "Read bytes: %zd", count)
+       DBG(3, "Read bytes: %zd", count);
 
        up(&sn9c102_sysfs_lock);
 
@@ -954,8 +976,8 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
        }
 
        DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
-           cam->sysfs.reg, value)
-       DBG(3, "Written bytes: %zd", count)
+           cam->sysfs.reg, value);
+       DBG(3, "Written bytes: %zd", count);
 
        up(&sn9c102_sysfs_lock);
 
@@ -979,7 +1001,7 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
 
        count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
 
-       DBG(3, "Read bytes: %zd", count)
+       DBG(3, "Read bytes: %zd", count);
 
        up(&sn9c102_sysfs_lock);
 
@@ -1011,8 +1033,8 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
 
        cam->sysfs.i2c_reg = index;
 
-       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg)
-       DBG(3, "Written bytes: %zd", count)
+       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
+       DBG(3, "Written bytes: %zd", count);
 
        up(&sn9c102_sysfs_lock);
 
@@ -1047,7 +1069,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
 
        count = sprintf(buf, "%d\n", val);
 
-       DBG(3, "Read bytes: %zd", count)
+       DBG(3, "Read bytes: %zd", count);
 
        up(&sn9c102_sysfs_lock);
 
@@ -1090,8 +1112,8 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
        }
 
        DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
-           cam->sysfs.i2c_reg, value)
-       DBG(3, "Written bytes: %zd", count)
+           cam->sysfs.i2c_reg, value);
+       DBG(3, "Written bytes: %zd", count);
 
        up(&sn9c102_sysfs_lock);
 
@@ -1193,7 +1215,7 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
        count = sizeof(cam->sysfs.frame_header);
        memcpy(buf, cam->sysfs.frame_header, count);
 
-       DBG(3, "Frame header, read bytes: %zd", count)
+       DBG(3, "Frame header, read bytes: %zd", count);
 
        return count;
 } 
@@ -1227,11 +1249,12 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
                video_device_create_file(v4ldev, &class_device_attr_blue);
                video_device_create_file(v4ldev, &class_device_attr_red);
        }
-       if (cam->sensor->sysfs_ops) {
+       if (cam->sensor && cam->sensor->sysfs_ops) {
                video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
                video_device_create_file(v4ldev, &class_device_attr_i2c_val);
        }
 }
+#endif /* CONFIG_VIDEO_ADV_DEBUG */
 
 /*****************************************************************************/
 
@@ -1281,7 +1304,7 @@ static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
        if (err)
                return -EIO;
 
-       PDBGG("Scaling factor: %u", scale)
+       PDBGG("Scaling factor: %u", scale);
 
        return 0;
 }
@@ -1304,7 +1327,7 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
                return -EIO;
 
        PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
-             "%u %u %u %u", h_start, v_start, h_size, v_size)
+             "%u %u %u %u", h_start, v_start, h_size, v_size);
 
        return 0;
 }
@@ -1336,7 +1359,7 @@ static int sn9c102_init(struct sn9c102_device* cam)
        if (s->init) {
                err = s->init(cam);
                if (err) {
-                       DBG(3, "Sensor initialization failed")
+                       DBG(3, "Sensor initialization failed");
                        return err;
                }
        }
@@ -1353,13 +1376,13 @@ static int sn9c102_init(struct sn9c102_device* cam)
 
        if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
                DBG(3, "Compressed video format is active, quality %d",
-                   cam->compression.quality)
+                   cam->compression.quality);
        else
-               DBG(3, "Uncompressed video format is active")
+               DBG(3, "Uncompressed video format is active");
 
        if (s->set_crop)
                if ((err = s->set_crop(cam, rect))) {
-                       DBG(3, "set_crop() failed")
+                       DBG(3, "set_crop() failed");
                        return err;
                }
 
@@ -1372,11 +1395,11 @@ static int sn9c102_init(struct sn9c102_device* cam)
                                err = s->set_ctrl(cam, &ctrl);
                                if (err) {
                                        DBG(3, "Set %s control failed",
-                                           s->qctrl[i].name)
+                                           s->qctrl[i].name);
                                        return err;
                                }
                                DBG(3, "Image sensor supports '%s' control",
-                                   s->qctrl[i].name)
+                                   s->qctrl[i].name);
                        }
        }
 
@@ -1392,7 +1415,7 @@ static int sn9c102_init(struct sn9c102_device* cam)
                cam->state |= DEV_INITIALIZED;
        }
 
-       DBG(2, "Initialization succeeded")
+       DBG(2, "Initialization succeeded");
        return 0;
 }
 
@@ -1401,7 +1424,7 @@ static void sn9c102_release_resources(struct sn9c102_device* cam)
 {
        down(&sn9c102_sysfs_lock);
 
-       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor)
+       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
 
@@ -1432,7 +1455,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
        }
 
        if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor)
+               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
                if ((filp->f_flags & O_NONBLOCK) ||
                    (filp->f_flags & O_NDELAY)) {
                        err = -EWOULDBLOCK;
@@ -1458,7 +1481,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
                err = sn9c102_init(cam);
                if (err) {
                        DBG(1, "Initialization failed again. "
-                              "I will retry on next open().")
+                              "I will retry on next open().");
                        goto out;
                }
                cam->state &= ~DEV_MISCONFIGURED;
@@ -1475,7 +1498,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
        cam->frame_count = 0;
        sn9c102_empty_framequeues(cam);
 
-       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor)
+       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
        up(&cam->dev_sem);
@@ -1504,7 +1527,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
        cam->users--;
        wake_up_interruptible_nr(&cam->open, 1);
 
-       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor)
+       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
        up(&cam->dev_sem);
 
@@ -1524,32 +1547,38 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present")
+               DBG(1, "Device not present");
                up(&cam->fileop_sem);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it again.")
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
                up(&cam->fileop_sem);
                return -EIO;
        }
 
        if (cam->io == IO_MMAP) {
                DBG(3, "Close and open the device again to choose "
-                      "the read method")
+                      "the read method");
                up(&cam->fileop_sem);
                return -EINVAL;
        }
 
        if (cam->io == IO_NONE) {
                if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
-                       DBG(1, "read() failed, not enough memory")
+                       DBG(1, "read() failed, not enough memory");
                        up(&cam->fileop_sem);
                        return -ENOMEM;
                }
                cam->io = IO_READ;
                cam->stream = STREAM_ON;
+       }
+
+       if (list_empty(&cam->inqueue)) {
+               if (!list_empty(&cam->outqueue))
+                       sn9c102_empty_framequeues(cam);
                sn9c102_queue_unusedframes(cam);
        }
 
@@ -1584,6 +1613,16 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 
        f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
 
+       if (count > f->buf.bytesused)
+               count = f->buf.bytesused;
+
+       if (copy_to_user(buf, f->bufmem, count)) {
+               err = -EFAULT;
+               goto exit;
+       }
+       *f_pos += count;
+
+exit:
        spin_lock_irqsave(&cam->queue_lock, lock_flags);
        list_for_each_entry(i, &cam->outqueue, frame)
                i->state = F_UNUSED;
@@ -1592,16 +1631,8 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 
        sn9c102_queue_unusedframes(cam);
 
-       if (count > f->buf.bytesused)
-               count = f->buf.bytesused;
-
-       if (copy_to_user(buf, f->bufmem, count)) {
-               up(&cam->fileop_sem);
-               return -EFAULT;
-       }
-       *f_pos += count;
-
-       PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index,count)
+       PDBGG("Frame #%lu, bytes read: %zu",
+             (unsigned long)f->buf.index, count);
 
        up(&cam->fileop_sem);
 
@@ -1612,33 +1643,42 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
 {
        struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_frame_t* f;
+       unsigned long lock_flags;
        unsigned int mask = 0;
 
        if (down_interruptible(&cam->fileop_sem))
                return POLLERR;
 
        if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present")
+               DBG(1, "Device not present");
                goto error;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it again.")
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
                goto error;
        }
 
        if (cam->io == IO_NONE) {
                if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
                                             IO_READ)) {
-                       DBG(1, "poll() failed, not enough memory")
+                       DBG(1, "poll() failed, not enough memory");
                        goto error;
                }
                cam->io = IO_READ;
                cam->stream = STREAM_ON;
        }
 
-       if (cam->io == IO_READ)
+       if (cam->io == IO_READ) {
+               spin_lock_irqsave(&cam->queue_lock, lock_flags);
+               list_for_each_entry(f, &cam->outqueue, frame)
+                       f->state = F_UNUSED;
+               INIT_LIST_HEAD(&cam->outqueue);
+               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
                sn9c102_queue_unusedframes(cam);
+       }
 
        poll_wait(filp, &cam->wait_frame, wait);
 
@@ -1680,22 +1720,22 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
 {
        struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
        unsigned long size = vma->vm_end - vma->vm_start,
-                     start = vma->vm_start,
-                     pos,
-                     page;
+                     start = vma->vm_start;
+       void *pos;
        u32 i;
 
        if (down_interruptible(&cam->fileop_sem))
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present")
+               DBG(1, "Device not present");
                up(&cam->fileop_sem);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it again.")
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
                up(&cam->fileop_sem);
                return -EIO;
        }
@@ -1715,15 +1755,12 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
                return -EINVAL;
        }
 
-       /* VM_IO is eventually going to replace PageReserved altogether */
        vma->vm_flags |= VM_IO;
-       vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+       vma->vm_flags |= VM_RESERVED;
 
-       pos = (unsigned long)cam->frame[i].bufmem;
+       pos = cam->frame[i].bufmem;
        while (size > 0) { /* size is page-aligned */
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE,
-                                   vma->vm_page_prot)) {
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
                        up(&cam->fileop_sem);
                        return -EAGAIN;
                }
@@ -1742,738 +1779,861 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
        return 0;
 }
 
+/*****************************************************************************/
 
-static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
-                              unsigned int cmd, void __user * arg)
+static int
+sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
 {
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-
-       switch (cmd) {
-
-       case VIDIOC_QUERYCAP:
-       {
-               struct v4l2_capability cap = {
-                       .driver = "sn9c102",
-                       .version = SN9C102_MODULE_VERSION_CODE,
-                       .capabilities = V4L2_CAP_VIDEO_CAPTURE | 
-                                       V4L2_CAP_READWRITE |
-                                       V4L2_CAP_STREAMING,
-               };
-
-               strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-               if (usb_make_path(cam->usbdev, cap.bus_info,
-                   sizeof(cap.bus_info)) < 0)
-                       strlcpy(cap.bus_info, cam->dev.bus_id,
-                               sizeof(cap.bus_info));
-
-               if (copy_to_user(arg, &cap, sizeof(cap)))
-                       return -EFAULT;
-
-               return 0;
-       }
-
-       case VIDIOC_ENUMINPUT:
-       {
-               struct v4l2_input i;
-
-               if (copy_from_user(&i, arg, sizeof(i)))
-                       return -EFAULT;
+       struct v4l2_capability cap = {
+               .driver = "sn9c102",
+               .version = SN9C102_MODULE_VERSION_CODE,
+               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING,
+       };
+
+       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+                       sizeof(cap.bus_info));
+
+       if (copy_to_user(arg, &cap, sizeof(cap)))
+               return -EFAULT;
 
-               if (i.index)
-                       return -EINVAL;
+       return 0;
+}
 
-               memset(&i, 0, sizeof(i));
-               strcpy(i.name, "USB");
 
-               if (copy_to_user(arg, &i, sizeof(i)))
-                       return -EFAULT;
+static int
+sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_input i;
 
-               return 0;
-       }
+       if (copy_from_user(&i, arg, sizeof(i)))
+               return -EFAULT;
 
-       case VIDIOC_G_INPUT:
-       case VIDIOC_S_INPUT:
-       {
-               int index;
+       if (i.index)
+               return -EINVAL;
 
-               if (copy_from_user(&index, arg, sizeof(index)))
-                       return -EFAULT;
+       memset(&i, 0, sizeof(i));
+       strcpy(i.name, "Camera");
 
-               if (index != 0)
-                       return -EINVAL;
+       if (copy_to_user(arg, &i, sizeof(i)))
+               return -EFAULT;
 
-               return 0;
-       }
+       return 0;
+}
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct sn9c102_sensor* s = cam->sensor;
-               struct v4l2_queryctrl qc;
-               u8 i;
 
-               if (copy_from_user(&qc, arg, sizeof(qc)))
-                       return -EFAULT;
+static int
+sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
+{
+       int index;
 
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (qc.id && qc.id == s->qctrl[i].id) {
-                               memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-                               if (copy_to_user(arg, &qc, sizeof(qc)))
-                                       return -EFAULT;
-                               return 0;
-                       }
+       if (copy_from_user(&index, arg, sizeof(index)))
+               return -EFAULT;
 
+       if (index != 0)
                return -EINVAL;
-       }
 
-       case VIDIOC_G_CTRL:
-       {
-               struct sn9c102_sensor* s = cam->sensor;
-               struct v4l2_control ctrl;
-               int err = 0;
+       return 0;
+}
 
-               if (!s->get_ctrl)
-                       return -EINVAL;
 
-               if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-                       return -EFAULT;
+static int
+sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = cam->sensor;
+       struct v4l2_queryctrl qc;
+       u8 i;
 
-               err = s->get_ctrl(cam, &ctrl);
+       if (copy_from_user(&qc, arg, sizeof(qc)))
+               return -EFAULT;
 
-               if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-                       return -EFAULT;
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (qc.id && qc.id == s->qctrl[i].id) {
+                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+                       if (copy_to_user(arg, &qc, sizeof(qc)))
+                               return -EFAULT;
+                       return 0;
+               }
 
-               return err;
-       }
+       return -EINVAL;
+}
 
-       case VIDIOC_S_CTRL_OLD:
-       case VIDIOC_S_CTRL:
-       {
-               struct sn9c102_sensor* s = cam->sensor;
-               struct v4l2_control ctrl;
-               u8 i;
-               int err = 0;
 
-               if (!s->set_ctrl)
-                       return -EINVAL;
+static int
+sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = cam->sensor;
+       struct v4l2_control ctrl;
+       int err = 0;
+       u8 i;
 
-               if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-                       return -EFAULT;
+       if (!s->get_ctrl && !s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
 
+       if (!s->get_ctrl) {
                for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (ctrl.id == s->qctrl[i].id) {
-                               if (ctrl.value < s->qctrl[i].minimum ||
-                                   ctrl.value > s->qctrl[i].maximum)
-                                       return -ERANGE;
-                               ctrl.value -= ctrl.value % s->qctrl[i].step;
-                               break;
+                       if (ctrl.id && ctrl.id == s->qctrl[i].id) {
+                               ctrl.value = s->_qctrl[i].default_value;
+                               goto exit;
                        }
+               return -EINVAL;
+       } else
+               err = s->get_ctrl(cam, &ctrl);
 
-               if ((err = s->set_ctrl(cam, &ctrl)))
-                       return err;
+exit:
+       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+               return -EFAULT;
 
-               s->_qctrl[i].default_value = ctrl.value;
+       return err;
+}
 
-               PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
-                     (unsigned long)ctrl.id, (unsigned long)ctrl.value)
 
-               return 0;
-       }
+static int
+sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = cam->sensor;
+       struct v4l2_control ctrl;
+       u8 i;
+       int err = 0;
 
-       case VIDIOC_CROPCAP:
-       {
-               struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
+       if (!s->set_ctrl)
+               return -EINVAL;
 
-               cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               cc->pixelaspect.numerator = 1;
-               cc->pixelaspect.denominator = 1;
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
 
-               if (copy_to_user(arg, cc, sizeof(*cc)))
-                       return -EFAULT;
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (ctrl.id == s->qctrl[i].id) {
+                       if (ctrl.value < s->qctrl[i].minimum ||
+                           ctrl.value > s->qctrl[i].maximum)
+                               return -ERANGE;
+                       ctrl.value -= ctrl.value % s->qctrl[i].step;
+                       break;
+               }
 
-               return 0;
-       }
+       if ((err = s->set_ctrl(cam, &ctrl)))
+               return err;
 
-       case VIDIOC_G_CROP:
-       {
-               struct sn9c102_sensor* s = cam->sensor;
-               struct v4l2_crop crop = {
-                       .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-               };
+       s->_qctrl[i].default_value = ctrl.value;
 
-               memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+       PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
+             (unsigned long)ctrl.id, (unsigned long)ctrl.value);
 
-               if (copy_to_user(arg, &crop, sizeof(crop)))
-                       return -EFAULT;
+       return 0;
+}
 
-               return 0;
-       }
 
-       case VIDIOC_S_CROP:
-       {
-               struct sn9c102_sensor* s = cam->sensor;
-               struct v4l2_crop crop;
-               struct v4l2_rect* rect;
-               struct v4l2_rect* bounds = &(s->cropcap.bounds);
-               struct v4l2_pix_format* pix_format = &(s->pix_format);
-               u8 scale;
-               const enum sn9c102_stream_state stream = cam->stream;
-               const u32 nbuffers = cam->nbuffers;
-               u32 i;
-               int err = 0;
-
-               if (copy_from_user(&crop, arg, sizeof(crop)))
-                       return -EFAULT;
+static int
+sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
 
-               rect = &(crop.c);
+       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cc->pixelaspect.numerator = 1;
+       cc->pixelaspect.denominator = 1;
 
-               if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
+       if (copy_to_user(arg, cc, sizeof(*cc)))
+               return -EFAULT;
 
-               if (cam->module_param.force_munmap)
-                       for (i = 0; i < cam->nbuffers; i++)
-                               if (cam->frame[i].vma_use_count) {
-                                       DBG(3, "VIDIOC_S_CROP failed. "
-                                              "Unmap the buffers first.")
-                                       return -EINVAL;
-                               }
+       return 0;
+}
 
-               /* Preserve R,G or B origin */
-               rect->left = (s->_rect.left & 1L) ?
-                            rect->left | 1L : rect->left & ~1L;
-               rect->top = (s->_rect.top & 1L) ?
-                           rect->top | 1L : rect->top & ~1L;
-
-               if (rect->width < 16)
-                       rect->width = 16;
-               if (rect->height < 16)
-                       rect->height = 16;
-               if (rect->width > bounds->width)
-                       rect->width = bounds->width;
-               if (rect->height > bounds->height)
-                       rect->height = bounds->height;
-               if (rect->left < bounds->left)
-                       rect->left = bounds->left;
-               if (rect->top < bounds->top)
-                       rect->top = bounds->top;
-               if (rect->left + rect->width > bounds->left + bounds->width)
-                       rect->left = bounds->left+bounds->width - rect->width;
-               if (rect->top + rect->height > bounds->top + bounds->height)
-                       rect->top = bounds->top+bounds->height - rect->height;
-
-               rect->width &= ~15L;
-               rect->height &= ~15L;
-
-               if (SN9C102_PRESERVE_IMGSCALE) {
-                       /* Calculate the actual scaling factor */
-                       u32 a, b;
-                       a = rect->width * rect->height;
-                       b = pix_format->width * pix_format->height;
-                       scale = b ? (u8)((a / b) < 4 ? 1 :
-                                       ((a / b) < 16 ? 2 : 4)) : 1;
-               } else
-                       scale = 1;
-
-               if (cam->stream == STREAM_ON)
-                       if ((err = sn9c102_stream_interrupt(cam)))
-                               return err;
-
-               if (copy_to_user(arg, &crop, sizeof(crop))) {
-                       cam->stream = stream;
-                       return -EFAULT;
-               }
 
-               if (cam->module_param.force_munmap || cam->io == IO_READ)
-                       sn9c102_release_buffers(cam);
+static int
+sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = cam->sensor;
+       struct v4l2_crop crop = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       };
 
-               err = sn9c102_set_crop(cam, rect);
-               if (s->set_crop)
-                       err += s->set_crop(cam, rect);
-               err += sn9c102_set_scale(cam, scale);
+       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
 
-               if (err) { /* atomic, no rollback in ioctl() */
-                       cam->state |= DEV_MISCONFIGURED;
-                       DBG(1, "VIDIOC_S_CROP failed because of hardware "
-                              "problems. To use the camera, close and open "
-                              "/dev/video%d again.", cam->v4ldev->minor)
-                       return -EIO;
-               }
+       if (copy_to_user(arg, &crop, sizeof(crop)))
+               return -EFAULT;
 
-               s->pix_format.width = rect->width/scale;
-               s->pix_format.height = rect->height/scale;
-               memcpy(&(s->_rect), rect, sizeof(*rect));
-
-               if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
-                   nbuffers != sn9c102_request_buffers(cam, nbuffers,
-                                                       cam->io)) {
-                       cam->state |= DEV_MISCONFIGURED;
-                       DBG(1, "VIDIOC_S_CROP failed because of not enough "
-                              "memory. To use the camera, close and open "
-                              "/dev/video%d again.", cam->v4ldev->minor)
-                       return -ENOMEM;
-               }
+       return 0;
+}
 
-               cam->stream = stream;
 
-               return 0;
-       }
+static int
+sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = cam->sensor;
+       struct v4l2_crop crop;
+       struct v4l2_rect* rect;
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_pix_format* pix_format = &(s->pix_format);
+       u8 scale;
+       const enum sn9c102_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
 
-       case VIDIOC_ENUM_FMT:
-       {
-               struct v4l2_fmtdesc fmtd;
+       if (copy_from_user(&crop, arg, sizeof(crop)))
+               return -EFAULT;
 
-               if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-                       return -EFAULT;
+       rect = &(crop.c);
 
-               if (fmtd.index == 0) {
-                       strcpy(fmtd.description, "bayer rgb");
-                       fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
-               } else if (fmtd.index == 1) {
-                       strcpy(fmtd.description, "compressed");
-                       fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
-                       fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-               } else
-                       return -EINVAL;
+       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
 
-               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_CROP failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
 
-               if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-                       return -EFAULT;
+       /* Preserve R,G or B origin */
+       rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
+       rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
+
+       if (rect->width < 16)
+               rect->width = 16;
+       if (rect->height < 16)
+               rect->height = 16;
+       if (rect->width > bounds->width)
+               rect->width = bounds->width;
+       if (rect->height > bounds->height)
+               rect->height = bounds->height;
+       if (rect->left < bounds->left)
+               rect->left = bounds->left;
+       if (rect->top < bounds->top)
+               rect->top = bounds->top;
+       if (rect->left + rect->width > bounds->left + bounds->width)
+               rect->left = bounds->left+bounds->width - rect->width;
+       if (rect->top + rect->height > bounds->top + bounds->height)
+               rect->top = bounds->top+bounds->height - rect->height;
+
+       rect->width &= ~15L;
+       rect->height &= ~15L;
+
+       if (SN9C102_PRESERVE_IMGSCALE) {
+               /* Calculate the actual scaling factor */
+               u32 a, b;
+               a = rect->width * rect->height;
+               b = pix_format->width * pix_format->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
+       } else
+               scale = 1;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
 
-               return 0;
+       if (copy_to_user(arg, &crop, sizeof(crop))) {
+               cam->stream = stream;
+               return -EFAULT;
        }
 
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format format;
-               struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
-
-               if (copy_from_user(&format, arg, sizeof(format)))
-                       return -EFAULT;
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               sn9c102_release_buffers(cam);
 
-               if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
+       err = sn9c102_set_crop(cam, rect);
+       if (s->set_crop)
+               err += s->set_crop(cam, rect);
+       err += sn9c102_set_scale(cam, scale);
 
-               pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
-                                    ? 0 : (pfmt->width * pfmt->priv) / 8;
-               pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-               pfmt->field = V4L2_FIELD_NONE;
-               memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
 
-               if (copy_to_user(arg, &format, sizeof(format)))
-                       return -EFAULT;
+       s->pix_format.width = rect->width/scale;
+       s->pix_format.height = rect->height/scale;
+       memcpy(&(s->_rect), rect, sizeof(*rect));
 
-               return 0;
+       if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
+           nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
        }
 
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT:
-       {
-               struct sn9c102_sensor* s = cam->sensor;
-               struct v4l2_format format;
-               struct v4l2_pix_format* pix;
-               struct v4l2_pix_format* pfmt = &(s->pix_format);
-               struct v4l2_rect* bounds = &(s->cropcap.bounds);
-               struct v4l2_rect rect;
-               u8 scale;
-               const enum sn9c102_stream_state stream = cam->stream;
-               const u32 nbuffers = cam->nbuffers;
-               u32 i;
-               int err = 0;
-
-               if (copy_from_user(&format, arg, sizeof(format)))
-                       return -EFAULT;
+       if (cam->io == IO_READ)
+               sn9c102_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               sn9c102_requeue_outqueue(cam);
 
-               pix = &(format.fmt.pix);
+       cam->stream = stream;
 
-               if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
-
-               memcpy(&rect, &(s->_rect), sizeof(rect));
+       return 0;
+}
 
-               { /* calculate the actual scaling factor */
-                       u32 a, b;
-                       a = rect.width * rect.height;
-                       b = pix->width * pix->height;
-                       scale = b ? (u8)((a / b) < 4 ? 1 :
-                                       ((a / b) < 16 ? 2 : 4)) : 1;
-               }
 
-               rect.width = scale * pix->width;
-               rect.height = scale * pix->height;
-
-               if (rect.width < 16)
-                       rect.width = 16;
-               if (rect.height < 16)
-                       rect.height = 16;
-               if (rect.width > bounds->left + bounds->width - rect.left)
-                       rect.width = bounds->left + bounds->width - rect.left;
-               if (rect.height > bounds->top + bounds->height - rect.top)
-                       rect.height = bounds->top + bounds->height - rect.top;
-
-               rect.width &= ~15L;
-               rect.height &= ~15L;
-
-               { /* adjust the scaling factor */
-                       u32 a, b;
-                       a = rect.width * rect.height;
-                       b = pix->width * pix->height;
-                       scale = b ? (u8)((a / b) < 4 ? 1 :
-                                       ((a / b) < 16 ? 2 : 4)) : 1;
-               }
+static int
+sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_fmtdesc fmtd;
 
-               pix->width = rect.width / scale;
-               pix->height = rect.height / scale;
-
-               if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
-                   pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
-                       pix->pixelformat = pfmt->pixelformat;
-               pix->priv = pfmt->priv; /* bpp */
-               pix->colorspace = pfmt->colorspace;
-               pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-                                   ? 0 : (pix->width * pix->priv) / 8;
-               pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-               pix->field = V4L2_FIELD_NONE;
-
-               if (cmd == VIDIOC_TRY_FMT) {
-                       if (copy_to_user(arg, &format, sizeof(format)))
-                               return -EFAULT;
-                       return 0;
-               }
+       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+               return -EFAULT;
 
-               if (cam->module_param.force_munmap)
-                       for (i = 0; i < cam->nbuffers; i++)
-                               if (cam->frame[i].vma_use_count) {
-                                       DBG(3, "VIDIOC_S_FMT failed. "
-                                              "Unmap the buffers first.")
-                                       return -EINVAL;
-                               }
+       if (fmtd.index == 0) {
+               strcpy(fmtd.description, "bayer rgb");
+               fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
+       } else if (fmtd.index == 1) {
+               strcpy(fmtd.description, "compressed");
+               fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+       } else
+               return -EINVAL;
 
-               if (cam->stream == STREAM_ON)
-                       if ((err = sn9c102_stream_interrupt(cam)))
-                               return err;
+       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
 
-               if (copy_to_user(arg, &format, sizeof(format))) {
-                       cam->stream = stream;
-                       return -EFAULT;
-               }
+       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+               return -EFAULT;
 
-               if (cam->module_param.force_munmap  || cam->io == IO_READ)
-                       sn9c102_release_buffers(cam);
-
-               err += sn9c102_set_pix_format(cam, pix);
-               err += sn9c102_set_crop(cam, &rect);
-               if (s->set_pix_format)
-                       err += s->set_pix_format(cam, pix);
-               if (s->set_crop)
-                       err += s->set_crop(cam, &rect);
-               err += sn9c102_set_scale(cam, scale);
-
-               if (err) { /* atomic, no rollback in ioctl() */
-                       cam->state |= DEV_MISCONFIGURED;
-                       DBG(1, "VIDIOC_S_FMT failed because of hardware "
-                              "problems. To use the camera, close and open "
-                              "/dev/video%d again.", cam->v4ldev->minor)
-                       return -EIO;
-               }
+       return 0;
+}
 
-               memcpy(pfmt, pix, sizeof(*pix));
-               memcpy(&(s->_rect), &rect, sizeof(rect));
 
-               if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-                   nbuffers != sn9c102_request_buffers(cam, nbuffers,
-                                                       cam->io)) {
-                       cam->state |= DEV_MISCONFIGURED;
-                       DBG(1, "VIDIOC_S_FMT failed because of not enough "
-                              "memory. To use the camera, close and open "
-                              "/dev/video%d again.", cam->v4ldev->minor)
-                       return -ENOMEM;
-               }
+static int
+sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_format format;
+       struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
 
-               cam->stream = stream;
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
 
-               return 0;
-       }
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
 
-       case VIDIOC_G_JPEGCOMP:
-       {
-               if (copy_to_user(arg, &cam->compression,
-                                sizeof(cam->compression)))
-                       return -EFAULT;
+       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
+                            ? 0 : (pfmt->width * pfmt->priv) / 8;
+       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+       pfmt->field = V4L2_FIELD_NONE;
+       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
 
-               return 0;
-       }
+       if (copy_to_user(arg, &format, sizeof(format)))
+               return -EFAULT;
 
-       case VIDIOC_S_JPEGCOMP:
-       {
-               struct v4l2_jpegcompression jc;
-               const enum sn9c102_stream_state stream = cam->stream;
-               int err = 0;
+       return 0;
+}
 
-               if (copy_from_user(&jc, arg, sizeof(jc)))
-                       return -EFAULT;
 
-               if (jc.quality != 0 && jc.quality != 1)
-                       return -EINVAL;
+static int
+sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
+                         void __user * arg)
+{
+       struct sn9c102_sensor* s = cam->sensor;
+       struct v4l2_format format;
+       struct v4l2_pix_format* pix;
+       struct v4l2_pix_format* pfmt = &(s->pix_format);
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_rect rect;
+       u8 scale;
+       const enum sn9c102_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
 
-               if (cam->stream == STREAM_ON)
-                       if ((err = sn9c102_stream_interrupt(cam)))
-                               return err;
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
 
-               err += sn9c102_set_compression(cam, &jc);
-               if (err) { /* atomic, no rollback in ioctl() */
-                       cam->state |= DEV_MISCONFIGURED;
-                       DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-                              "problems. To use the camera, close and open "
-                              "/dev/video%d again.", cam->v4ldev->minor)
-                       return -EIO;
-               }
+       pix = &(format.fmt.pix);
 
-               cam->compression.quality = jc.quality;
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
 
-               cam->stream = stream;
+       memcpy(&rect, &(s->_rect), sizeof(rect));
 
-               return 0;
+       { /* calculate the actual scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
        }
 
-       case VIDIOC_REQBUFS:
-       {
-               struct v4l2_requestbuffers rb;
-               u32 i;
-               int err;
+       rect.width = scale * pix->width;
+       rect.height = scale * pix->height;
 
-               if (copy_from_user(&rb, arg, sizeof(rb)))
-                       return -EFAULT;
+       if (rect.width < 16)
+               rect.width = 16;
+       if (rect.height < 16)
+               rect.height = 16;
+       if (rect.width > bounds->left + bounds->width - rect.left)
+               rect.width = bounds->left + bounds->width - rect.left;
+       if (rect.height > bounds->top + bounds->height - rect.top)
+               rect.height = bounds->top + bounds->height - rect.top;
 
-               if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                   rb.memory != V4L2_MEMORY_MMAP)
-                       return -EINVAL;
+       rect.width &= ~15L;
+       rect.height &= ~15L;
 
-               if (cam->io == IO_READ) {
-                       DBG(3, "Close and open the device again to choose "
-                              "the mmap I/O method")
-                       return -EINVAL;
-               }
+       { /* adjust the scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
+       }
+
+       pix->width = rect.width / scale;
+       pix->height = rect.height / scale;
+
+       if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
+           pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+               pix->pixelformat = pfmt->pixelformat;
+       pix->priv = pfmt->priv; /* bpp */
+       pix->colorspace = pfmt->colorspace;
+       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+                           ? 0 : (pix->width * pix->priv) / 8;
+       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+       pix->field = V4L2_FIELD_NONE;
+
+       if (cmd == VIDIOC_TRY_FMT) {
+               if (copy_to_user(arg, &format, sizeof(format)))
+                       return -EFAULT;
+               return 0;
+       }
 
+       if (cam->module_param.force_munmap)
                for (i = 0; i < cam->nbuffers; i++)
                        if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_REQBUFS failed. "
-                                      "Previous buffers are still mapped.")
+                               DBG(3, "VIDIOC_S_FMT failed. Unmap the "
+                                      "buffers first.");
                                return -EINVAL;
                        }
 
-               if (cam->stream == STREAM_ON)
-                       if ((err = sn9c102_stream_interrupt(cam)))
-                               return err;
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
 
-               sn9c102_empty_framequeues(cam);
+       if (copy_to_user(arg, &format, sizeof(format))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
 
+       if (cam->module_param.force_munmap  || cam->io == IO_READ)
                sn9c102_release_buffers(cam);
-               if (rb.count)
-                       rb.count = sn9c102_request_buffers(cam, rb.count,
-                                                          IO_MMAP);
 
-               if (copy_to_user(arg, &rb, sizeof(rb))) {
-                       sn9c102_release_buffers(cam);
-                       cam->io = IO_NONE;
-                       return -EFAULT;
-               }
+       err += sn9c102_set_pix_format(cam, pix);
+       err += sn9c102_set_crop(cam, &rect);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, pix);
+       if (s->set_crop)
+               err += s->set_crop(cam, &rect);
+       err += sn9c102_set_scale(cam, scale);
 
-               cam->io = rb.count ? IO_MMAP : IO_NONE;
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
 
-               return 0;
+       memcpy(pfmt, pix, sizeof(*pix));
+       memcpy(&(s->_rect), &rect, sizeof(rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
        }
 
-       case VIDIOC_QUERYBUF:
-       {
-               struct v4l2_buffer b;
+       if (cam->io == IO_READ)
+               sn9c102_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               sn9c102_requeue_outqueue(cam);
 
-               if (copy_from_user(&b, arg, sizeof(b)))
-                       return -EFAULT;
+       cam->stream = stream;
 
-               if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                   b.index >= cam->nbuffers || cam->io != IO_MMAP)
-                       return -EINVAL;
+       return 0;
+}
 
-               memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
 
-               if (cam->frame[b.index].vma_use_count)
-                       b.flags |= V4L2_BUF_FLAG_MAPPED;
+static int
+sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
+{
+       if (copy_to_user(arg, &cam->compression,
+                        sizeof(cam->compression)))
+               return -EFAULT;
 
-               if (cam->frame[b.index].state == F_DONE)
-                       b.flags |= V4L2_BUF_FLAG_DONE;
-               else if (cam->frame[b.index].state != F_UNUSED)
-                       b.flags |= V4L2_BUF_FLAG_QUEUED;
+       return 0;
+}
 
-               if (copy_to_user(arg, &b, sizeof(b)))
-                       return -EFAULT;
 
-               return 0;
+static int
+sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_jpegcompression jc;
+       const enum sn9c102_stream_state stream = cam->stream;
+       int err = 0;
+
+       if (copy_from_user(&jc, arg, sizeof(jc)))
+               return -EFAULT;
+
+       if (jc.quality != 0 && jc.quality != 1)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       err += sn9c102_set_compression(cam, &jc);
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+                      "problems. To use the camera, close and open "
+                      "/dev/video%d again.", cam->v4ldev->minor);
+               return -EIO;
        }
 
-       case VIDIOC_QBUF:
-       {
-               struct v4l2_buffer b;
-               unsigned long lock_flags;
+       cam->compression.quality = jc.quality;
 
-               if (copy_from_user(&b, arg, sizeof(b)))
-                       return -EFAULT;
+       cam->stream = stream;
 
-               if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                   b.index >= cam->nbuffers || cam->io != IO_MMAP)
-                       return -EINVAL;
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_requestbuffers rb;
+       u32 i;
+       int err;
+
+       if (copy_from_user(&rb, arg, sizeof(rb)))
+               return -EFAULT;
+
+       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           rb.memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
 
-               if (cam->frame[b.index].state != F_UNUSED)
+       if (cam->io == IO_READ) {
+               DBG(3, "Close and open the device again to choose the mmap "
+                      "I/O method");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].vma_use_count) {
+                       DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
+                              "still mapped.");
                        return -EINVAL;
+               }
 
-               cam->frame[b.index].state = F_QUEUED;
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
 
-               spin_lock_irqsave(&cam->queue_lock, lock_flags);
-               list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+       sn9c102_empty_framequeues(cam);
 
-               PDBGG("Frame #%lu queued", (unsigned long)b.index)
+       sn9c102_release_buffers(cam);
+       if (rb.count)
+               rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP);
 
-               return 0;
+       if (copy_to_user(arg, &rb, sizeof(rb))) {
+               sn9c102_release_buffers(cam);
+               cam->io = IO_NONE;
+               return -EFAULT;
        }
 
-       case VIDIOC_DQBUF:
-       {
-               struct v4l2_buffer b;
-               struct sn9c102_frame_t *f;
-               unsigned long lock_flags;
-               int err = 0;
+       cam->io = rb.count ? IO_MMAP : IO_NONE;
 
-               if (copy_from_user(&b, arg, sizeof(b)))
-                       return -EFAULT;
+       return 0;
+}
 
-               if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
-                       return -EINVAL;
 
-               if (list_empty(&cam->outqueue)) {
-                       if (cam->stream == STREAM_OFF)
-                               return -EINVAL;
-                       if (filp->f_flags & O_NONBLOCK)
-                               return -EAGAIN;
-                       err = wait_event_interruptible
-                             ( cam->wait_frame, 
-                               (!list_empty(&cam->outqueue)) ||
-                               (cam->state & DEV_DISCONNECTED) ||
-                               (cam->state & DEV_MISCONFIGURED) );
-                       if (err)
-                               return err;
-                       if (cam->state & DEV_DISCONNECTED)
-                               return -ENODEV;
-                       if (cam->state & DEV_MISCONFIGURED)
-                               return -EIO;
-               }
+static int
+sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
 
-               spin_lock_irqsave(&cam->queue_lock, lock_flags);
-               f = list_entry(cam->outqueue.next, struct sn9c102_frame_t,
-                              frame);
-               list_del(cam->outqueue.next);
-               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
 
-               f->state = F_UNUSED;
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
 
-               memcpy(&b, &f->buf, sizeof(b));
-               if (f->vma_use_count)
-                       b.flags |= V4L2_BUF_FLAG_MAPPED;
+       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
 
-               if (copy_to_user(arg, &b, sizeof(b)))
-                       return -EFAULT;
+       if (cam->frame[b.index].vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
 
-               PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index)
+       if (cam->frame[b.index].state == F_DONE)
+               b.flags |= V4L2_BUF_FLAG_DONE;
+       else if (cam->frame[b.index].state != F_UNUSED)
+               b.flags |= V4L2_BUF_FLAG_QUEUED;
 
-               return 0;
-       }
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
 
-       case VIDIOC_STREAMON:
-       {
-               int type;
+       return 0;
+}
 
-               if (copy_from_user(&type, arg, sizeof(type)))
-                       return -EFAULT;
 
-               if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-                       return -EINVAL;
+static int
+sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+       unsigned long lock_flags;
 
-               if (list_empty(&cam->inqueue))
-                       return -EINVAL;
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
 
-               cam->stream = STREAM_ON;
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
 
-               DBG(3, "Stream on")
+       if (cam->frame[b.index].state != F_UNUSED)
+               return -EINVAL;
 
-               return 0;
-       }
+       cam->frame[b.index].state = F_QUEUED;
 
-       case VIDIOC_STREAMOFF:
-       {
-               int type, err;
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
 
-               if (copy_from_user(&type, arg, sizeof(type)))
-                       return -EFAULT;
+       PDBGG("Frame #%lu queued", (unsigned long)b.index);
 
-               if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-                       return -EINVAL;
+       return 0;
+}
 
-               if (cam->stream == STREAM_ON)
-                       if ((err = sn9c102_stream_interrupt(cam)))
-                               return err;
 
-               sn9c102_empty_framequeues(cam);
+static int
+sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
+                     void __user * arg)
+{
+       struct v4l2_buffer b;
+       struct sn9c102_frame_t *f;
+       unsigned long lock_flags;
+       int err = 0;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
 
-               DBG(3, "Stream off")
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
 
-               return 0;
+       if (list_empty(&cam->outqueue)) {
+               if (cam->stream == STREAM_OFF)
+                       return -EINVAL;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               err = wait_event_interruptible
+                     ( cam->wait_frame,
+                       (!list_empty(&cam->outqueue)) ||
+                       (cam->state & DEV_DISCONNECTED) ||
+                       (cam->state & DEV_MISCONFIGURED) );
+               if (err)
+                       return err;
+               if (cam->state & DEV_DISCONNECTED)
+                       return -ENODEV;
+               if (cam->state & DEV_MISCONFIGURED)
+                       return -EIO;
        }
 
-       case VIDIOC_G_PARM:
-       {
-               struct v4l2_streamparm sp;
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame);
+       list_del(cam->outqueue.next);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
 
-               if (copy_from_user(&sp, arg, sizeof(sp)))
-                       return -EFAULT;
+       f->state = F_UNUSED;
 
-               if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
+       memcpy(&b, &f->buf, sizeof(b));
+       if (f->vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
+{
+       int type;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->inqueue))
+               return -EINVAL;
+
+       cam->stream = STREAM_ON;
+
+       DBG(3, "Stream on");
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
+{
+       int type, err;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       sn9c102_empty_framequeues(cam);
+
+       DBG(3, "Stream off");
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+       sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
 
-               sp.parm.capture.extendedmode = 0;
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+
+       if (sp.parm.capture.readbuffers == 0)
                sp.parm.capture.readbuffers = cam->nreadbuffers;
 
-               if (copy_to_user(arg, &sp, sizeof(sp)))
-                       return -EFAULT;
+       if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
+               sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
 
-               return 0;
-       }
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
 
-       case VIDIOC_S_PARM_OLD:
-       case VIDIOC_S_PARM:
-       {
-               struct v4l2_streamparm sp;
+       cam->nreadbuffers = sp.parm.capture.readbuffers;
 
-               if (copy_from_user(&sp, arg, sizeof(sp)))
-                       return -EFAULT;
+       return 0;
+}
 
-               if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       return -EINVAL;
 
-               sp.parm.capture.extendedmode = 0;
+static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
+                              unsigned int cmd, void __user * arg)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
 
-               if (sp.parm.capture.readbuffers == 0)
-                       sp.parm.capture.readbuffers = cam->nreadbuffers;
+       case VIDIOC_QUERYCAP:
+               return sn9c102_vidioc_querycap(cam, arg);
 
-               if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
-                       sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
+       case VIDIOC_ENUMINPUT:
+               return sn9c102_vidioc_enuminput(cam, arg);
 
-               if (copy_to_user(arg, &sp, sizeof(sp)))
-                       return -EFAULT;
+       case VIDIOC_G_INPUT:
+       case VIDIOC_S_INPUT:
+               return sn9c102_vidioc_gs_input(cam, arg);
 
-               cam->nreadbuffers = sp.parm.capture.readbuffers;
+       case VIDIOC_QUERYCTRL:
+               return sn9c102_vidioc_query_ctrl(cam, arg);
 
-               return 0;
-       }
+       case VIDIOC_G_CTRL:
+               return sn9c102_vidioc_g_ctrl(cam, arg);
+
+       case VIDIOC_S_CTRL_OLD:
+       case VIDIOC_S_CTRL:
+               return sn9c102_vidioc_s_ctrl(cam, arg);
+
+       case VIDIOC_CROPCAP_OLD:
+       case VIDIOC_CROPCAP:
+               return sn9c102_vidioc_cropcap(cam, arg);
+
+       case VIDIOC_G_CROP:
+               return sn9c102_vidioc_g_crop(cam, arg);
+
+       case VIDIOC_S_CROP:
+               return sn9c102_vidioc_s_crop(cam, arg);
+
+       case VIDIOC_ENUM_FMT:
+               return sn9c102_vidioc_enum_fmt(cam, arg);
+
+       case VIDIOC_G_FMT:
+               return sn9c102_vidioc_g_fmt(cam, arg);
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+               return sn9c102_vidioc_try_s_fmt(cam, cmd, arg);
+
+       case VIDIOC_G_JPEGCOMP:
+               return sn9c102_vidioc_g_jpegcomp(cam, arg);
+
+       case VIDIOC_S_JPEGCOMP:
+               return sn9c102_vidioc_s_jpegcomp(cam, arg);
+
+       case VIDIOC_REQBUFS:
+               return sn9c102_vidioc_reqbufs(cam, arg);
+
+       case VIDIOC_QUERYBUF:
+               return sn9c102_vidioc_querybuf(cam, arg);
+
+       case VIDIOC_QBUF:
+               return sn9c102_vidioc_qbuf(cam, arg);
+
+       case VIDIOC_DQBUF:
+               return sn9c102_vidioc_dqbuf(cam, filp, arg);
+
+       case VIDIOC_STREAMON:
+               return sn9c102_vidioc_streamon(cam, arg);
+
+       case VIDIOC_STREAMOFF:
+               return sn9c102_vidioc_streamoff(cam, arg);
+
+       case VIDIOC_G_PARM:
+               return sn9c102_vidioc_g_parm(cam, arg);
+
+       case VIDIOC_S_PARM_OLD:
+       case VIDIOC_S_PARM:
+               return sn9c102_vidioc_s_parm(cam, arg);
 
        case VIDIOC_G_STD:
        case VIDIOC_S_STD:
@@ -2499,17 +2659,20 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
                return -ERESTARTSYS;
 
        if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present")
+               DBG(1, "Device not present");
                up(&cam->fileop_sem);
                return -ENODEV;
        }
 
        if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it again.")
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
                up(&cam->fileop_sem);
                return -EIO;
        }
 
+       V4LDBG(3, "sn9c102", cmd);
+
        err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
 
        up(&cam->fileop_sem);
@@ -2517,9 +2680,10 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
        return err;
 }
 
+/*****************************************************************************/
 
 static struct file_operations sn9c102_fops = {
-       .owner =   THIS_MODULE,
+       .owner = THIS_MODULE,
        .open =    sn9c102_open,
        .release = sn9c102_release,
        .ioctl =   sn9c102_ioctl,
@@ -2538,36 +2702,22 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        struct usb_device *udev = interface_to_usbdev(intf);
        struct sn9c102_device* cam;
        static unsigned int dev_nr = 0;
-       unsigned int i, n;
+       unsigned int i;
        int err = 0, r;
 
-       n = ARRAY_SIZE(sn9c102_id_table);
-       for (i = 0; i < n-1; i++)
-               if (le16_to_cpu(udev->descriptor.idVendor) == 
-                   sn9c102_id_table[i].idVendor &&
-                   le16_to_cpu(udev->descriptor.idProduct) ==
-                   sn9c102_id_table[i].idProduct)
-                       break;
-       if (i == n-1)
-               return -ENODEV;
-
-       if (!(cam = kmalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
+       if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
                return -ENOMEM;
-       memset(cam, 0, sizeof(*cam));
 
        cam->usbdev = udev;
 
-       memcpy(&cam->dev, &udev->dev, sizeof(struct device));
-
-       if (!(cam->control_buffer = kmalloc(8, GFP_KERNEL))) {
-               DBG(1, "kmalloc() failed")
+       if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
+               DBG(1, "kmalloc() failed");
                err = -ENOMEM;
                goto fail;
        }
-       memset(cam->control_buffer, 0, 8);
 
        if (!(cam->v4ldev = video_device_alloc())) {
-               DBG(1, "video_device_alloc() failed")
+               DBG(1, "video_device_alloc() failed");
                err = -ENOMEM;
                goto fail;
        }
@@ -2577,25 +2727,22 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        r = sn9c102_read_reg(cam, 0x00);
        if (r < 0 || r != 0x10) {
                DBG(1, "Sorry, this is not a SN9C10x based camera "
-                      "(vid/pid 0x%04X/0x%04X)",
-                   sn9c102_id_table[i].idVendor,sn9c102_id_table[i].idProduct)
+                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
                err = -ENODEV;
                goto fail;
        }
 
-       cam->bridge = (sn9c102_id_table[i].idProduct & 0xffc0) == 0x6080 ?
+       cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
                      BRIDGE_SN9C103 : BRIDGE_SN9C102;
        switch (cam->bridge) {
        case BRIDGE_SN9C101:
        case BRIDGE_SN9C102:
                DBG(2, "SN9C10[12] PC Camera Controller detected "
-                      "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,
-                   sn9c102_id_table[i].idProduct)
+                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
                break;
        case BRIDGE_SN9C103:
                DBG(2, "SN9C103 PC Camera Controller detected "
-                      "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,
-                   sn9c102_id_table[i].idProduct)
+                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
                break;
        }
 
@@ -2606,24 +2753,24 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        }
 
        if (!err && cam->sensor) {
-               DBG(2, "%s image sensor detected", cam->sensor->name)
+               DBG(2, "%s image sensor detected", cam->sensor->name);
                DBG(3, "Support for %s maintained by %s",
-                   cam->sensor->name, cam->sensor->maintainer)
+                   cam->sensor->name, cam->sensor->maintainer);
        } else {
-               DBG(1, "No supported image sensor detected")
+               DBG(1, "No supported image sensor detected");
                err = -ENODEV;
                goto fail;
        }
 
        if (sn9c102_init(cam)) {
-               DBG(1, "Initialization failed. I will retry on open().")
+               DBG(1, "Initialization failed. I will retry on open().");
                cam->state |= DEV_MISCONFIGURED;
        }
 
        strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
        cam->v4ldev->owner = THIS_MODULE;
        cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = VID_HARDWARE_SN9C102;
+       cam->v4ldev->hardware = 0;
        cam->v4ldev->fops = &sn9c102_fops;
        cam->v4ldev->minor = video_nr[dev_nr];
        cam->v4ldev->release = video_device_release;
@@ -2634,23 +2781,25 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
        err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
                                    video_nr[dev_nr]);
        if (err) {
-               DBG(1, "V4L2 device registration failed")
+               DBG(1, "V4L2 device registration failed");
                if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(1, "Free /dev/videoX node not found")
+                       DBG(1, "Free /dev/videoX node not found");
                video_nr[dev_nr] = -1;
                dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
                up(&cam->dev_sem);
                goto fail;
        }
 
-       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor)
+       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
 
        cam->module_param.force_munmap = force_munmap[dev_nr];
 
        dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
        sn9c102_create_sysfs(cam);
-       DBG(2, "Optional device control through 'sysfs' interface ready")
+       DBG(2, "Optional device control through 'sysfs' interface ready");
+#endif
 
        usb_set_intfdata(intf, cam);
 
@@ -2680,14 +2829,14 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
 
        down(&cam->dev_sem); 
 
-       DBG(2, "Disconnecting %s...", cam->v4ldev->name)
+       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
        wake_up_interruptible_all(&cam->open);
 
        if (cam->users) {
                DBG(2, "Device /dev/video%d is open! Deregistration and "
                       "memory deallocation are deferred on close.",
-                   cam->v4ldev->minor)
+                   cam->v4ldev->minor);
                cam->state |= DEV_MISCONFIGURED;
                sn9c102_stop_transfer(cam);
                cam->state |= DEV_DISCONNECTED;
@@ -2720,11 +2869,11 @@ static int __init sn9c102_module_init(void)
 {
        int err = 0;
 
-       KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION)
-       KDBG(3, SN9C102_MODULE_AUTHOR)
+       KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION);
+       KDBG(3, SN9C102_MODULE_AUTHOR);
 
        if ((err = usb_register(&sn9c102_usb_driver)))
-               KDBG(1, "usb_register() failed")
+               KDBG(1, "usb_register() failed");
 
        return err;
 }
index 18070d5333cfac6df58fe9812704a767be62fa2e..46c12ec3ca6235c729ca9452fe43a11f25e32fa9 100644 (file)
@@ -2,7 +2,7 @@
  * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera     *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
index 86676abf3547819d29813ea9532838c9d5f43c40..d9aa7a61095d3e5b3833dc7fb47f54360c98cb9f 100644 (file)
@@ -2,7 +2,7 @@
  * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera     *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
index d27c5aedeaf89fd08984c85671e36d99b0184bee..4a36519b5af40f067c05d80c3c1310cd01a4d612 100644 (file)
@@ -2,7 +2,7 @@
  * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera      *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2005 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
@@ -375,8 +375,10 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam)
 
        sn9c102_attach_sensor(cam, &ov7630);
 
-       if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
-           le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c)
+       if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c &&
+           le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602d &&
+           le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
+           le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x60b0)
                return -ENODEV;
 
        err += sn9c102_write_reg(cam, 0x01, 0x01);
index 48e3ec39d4e20a8006edcc014674cd63478aa999..b1dee78abe04ba961da5fc846a7ffde87d9d9adf 100644 (file)
@@ -2,7 +2,7 @@
  * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera     *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
index a45166c3488ca3c3177852e92ebd88ef5d308e3c..7d953b24f2f2a168cc52fe30c06e53c090c35bfc 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************************
  * API for image sensors connected to the SN9C10x PC Camera Controllers    *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
@@ -92,7 +92,18 @@ extern void
 sn9c102_attach_sensor(struct sn9c102_device* cam,
                       struct sn9c102_sensor* sensor);
 
-/* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/
+/*
+   Each SN9C10x camera has proper PID/VID identifiers.
+   SN9C103 supports multiple interfaces, but we only handle the video class
+   interface.
+*/
+#define SN9C102_USB_DEVICE(vend, prod, intclass)                              \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
+                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
+       .idVendor = (vend),                                                   \
+       .idProduct = (prod),                                                  \
+       .bInterfaceClass = (intclass)
+
 #define SN9C102_ID_TABLE                                                      \
 static const struct usb_device_id sn9c102_id_table[] = {                      \
        { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
@@ -107,33 +118,34 @@ static const struct usb_device_id sn9c102_id_table[] = {                      \
        { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */                        \
        { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */                         \
        { USB_DEVICE(0x0c45, 0x602d), },                                      \
+       { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */                         \
        { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */                          \
-       { USB_DEVICE(0x0c45, 0x6080), },                                      \
-       { USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */              \
-       { USB_DEVICE(0x0c45, 0x6083), }, /* HV7131[D|E1] */                   \
-       { USB_DEVICE(0x0c45, 0x6088), },                                      \
-       { USB_DEVICE(0x0c45, 0x608a), },                                      \
-       { USB_DEVICE(0x0c45, 0x608b), },                                      \
-       { USB_DEVICE(0x0c45, 0x608c), }, /* HV7131x */                        \
-       { USB_DEVICE(0x0c45, 0x608e), }, /* CIS-VF10 */                       \
-       { USB_DEVICE(0x0c45, 0x608f), }, /* OV7630 */                         \
-       { USB_DEVICE(0x0c45, 0x60a0), },                                      \
-       { USB_DEVICE(0x0c45, 0x60a2), },                                      \
-       { USB_DEVICE(0x0c45, 0x60a3), },                                      \
-       { USB_DEVICE(0x0c45, 0x60a8), }, /* PAS106B */                        \
-       { USB_DEVICE(0x0c45, 0x60aa), }, /* TAS5130D1B */                     \
-       { USB_DEVICE(0x0c45, 0x60ab), }, /* TAS5110C1B */                     \
-       { USB_DEVICE(0x0c45, 0x60ac), },                                      \
-       { USB_DEVICE(0x0c45, 0x60ae), },                                      \
-       { USB_DEVICE(0x0c45, 0x60af), }, /* PAS202BCB */                      \
-       { USB_DEVICE(0x0c45, 0x60b0), },                                      \
-       { USB_DEVICE(0x0c45, 0x60b2), },                                      \
-       { USB_DEVICE(0x0c45, 0x60b3), },                                      \
-       { USB_DEVICE(0x0c45, 0x60b8), },                                      \
-       { USB_DEVICE(0x0c45, 0x60ba), },                                      \
-       { USB_DEVICE(0x0c45, 0x60bb), },                                      \
-       { USB_DEVICE(0x0c45, 0x60bc), },                                      \
-       { USB_DEVICE(0x0c45, 0x60be), },                                      \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */  \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */     \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131x */          \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */          \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */       \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */       \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */       \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), },                        \
        { }                                                                   \
 };
 
@@ -177,16 +189,18 @@ extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value);
 extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address);
 
 /* I/O on registers in the bridge. Could be used by the sensor methods too */
+extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
 extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
 extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
 
 /*
    NOTE: there are no exported debugging functions. To uniform the output you
    must use the dev_info()/dev_warn()/dev_err() macros defined in device.h,
-   already included here, the argument being the struct device 'dev' of the
-   sensor structure. Do NOT use these macros before the sensor is attached or
-   the kernel will crash! However, you should not need to notify the user about
-   common errors or other messages, since this is done by the master module.
+   already included here, the argument being the struct device '&usbdev->dev'
+   of the sensor structure. Do NOT use these macros before the sensor is
+   attached or the kernel will crash! However, you should not need to notify
+   the user about common errors or other messages, since this is done by the
+   master module.
 */
 
 /*****************************************************************************/
@@ -345,13 +359,6 @@ struct sn9c102_sensor {
           error code without rolling back.
        */
 
-       const struct device* dev;
-       /*
-          This is the argument for dev_err(), dev_info() and dev_warn(). It
-          is used for debugging purposes. You must not access the struct
-          before the sensor is attached.
-       */
-
        const struct usb_device* usbdev;
        /*
           Points to the usb_device struct after the sensor is attached.
index 8775999b5aff7e6410419958ab0c4f6e04bb861a..32ddf236cafed990b242404473cc3dc41f82f102 100644 (file)
@@ -2,7 +2,7 @@
  * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera  *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
index 927eafdd8c73e1541f93381637bcaf479019b32b..a0728f0ae00cdd72ea5890aab6835176f9e192fb 100644 (file)
@@ -2,7 +2,7 @@
  * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera  *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
index bff9434c8e5578fcf0648dc6c6e09356e61613aa..9937fc64c8bf3c34a3e7a31b1cedaf0ee22065b3 100644 (file)
@@ -62,7 +62,6 @@ MODULE_LICENSE(W9968CF_MODULE_LICENSE);
 MODULE_SUPPORTED_DEVICE("Video");
 
 static int ovmod_load = W9968CF_OVMOD_LOAD;
-static int vppmod_load = W9968CF_VPPMOD_LOAD;
 static unsigned short simcams = W9968CF_SIMCAMS;
 static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
 static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
@@ -107,7 +106,6 @@ static unsigned int param_nv[24]; /* number of values per parameter */
 
 #ifdef CONFIG_KMOD
 module_param(ovmod_load, bool, 0644);
-module_param(vppmod_load, bool, 0444);
 #endif
 module_param(simcams, ushort, 0644);
 module_param_array(video_nr, short, &param_nv[0], 0444);
@@ -150,18 +148,6 @@ MODULE_PARM_DESC(ovmod_load,
                  "\ninto memory."
                  "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
                  "\n");
-MODULE_PARM_DESC(vppmod_load, 
-                 "\n<0|1> Automatic 'w9968cf-vpp' module loading."
-                 "\n0 disabled, 1 enabled."
-                 "\nIf enabled, every time an application attempts to open a"
-                 "\ncamera, 'insmod' searches for the video post-processing"
-                 "\nmodule in the system and loads it automatically (if"
-                 "\npresent). The optional 'w9968cf-vpp' module adds extra"
-                 "\n image manipulation functions to the 'w9968cf' module,like"
-                 "\nsoftware up-scaling,colour conversions and video decoding"
-                 "\nfor very high frame rates."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_VPPMOD_LOAD)"."
-                 "\n");
 #endif
 MODULE_PARM_DESC(simcams, 
                  "\n<n> Number of cameras allowed to stream simultaneously."
@@ -492,10 +478,6 @@ static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
 static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
 static void w9968cf_release_resources(struct w9968cf_device*);
 
-/* Intermodule communication */
-static int w9968cf_vppmod_detect(struct w9968cf_device*);
-static void w9968cf_vppmod_release(struct w9968cf_device*);
-
 
 
 /****************************************************************************
@@ -2737,9 +2719,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
        cam->streaming = 0;
        cam->misconfigured = 0;
 
-       if (!w9968cf_vpp)
-               if ((err = w9968cf_vppmod_detect(cam)))
-                       goto out;
+       w9968cf_adjust_configuration(cam);
 
        if ((err = w9968cf_allocate_memory(cam)))
                goto deallocate_memory;
@@ -2766,7 +2746,6 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
 
 deallocate_memory:
        w9968cf_deallocate_memory(cam);
-out:
        DBG(2, "Failed to open the video device")
        up(&cam->dev_sem);
        up_read(&w9968cf_disconnect);
@@ -2784,8 +2763,6 @@ static int w9968cf_release(struct inode* inode, struct file* filp)
 
        w9968cf_stop_transfer(cam);
 
-       w9968cf_vppmod_release(cam);
-
        if (cam->disconnected) {
                w9968cf_release_resources(cam);
                up(&cam->dev_sem);
@@ -3681,106 +3658,6 @@ static struct usb_driver w9968cf_usb_driver = {
  * Module init, exit and intermodule communication                          *
  ****************************************************************************/
 
-static int w9968cf_vppmod_detect(struct w9968cf_device* cam)
-{
-       if (!w9968cf_vpp)
-               if (vppmod_load)
-                       request_module("w9968cf-vpp");
-
-       down(&w9968cf_vppmod_lock);
-
-       if (!w9968cf_vpp) {
-               DBG(4, "Video post-processing module not detected")
-               w9968cf_adjust_configuration(cam);
-               goto out;
-       }
-
-       if (!try_module_get(w9968cf_vpp->owner)) {
-               DBG(1, "Couldn't increment the reference count of "
-                      "the video post-processing module")
-               up(&w9968cf_vppmod_lock);
-               return -ENOSYS;
-       }
-
-       w9968cf_vpp->busy++;
-
-       DBG(5, "Video post-processing module detected")
-
-out:
-       up(&w9968cf_vppmod_lock);
-       return 0;
-}
-
-
-static void w9968cf_vppmod_release(struct w9968cf_device* cam)
-{
-       down(&w9968cf_vppmod_lock);
-
-       if (w9968cf_vpp && w9968cf_vpp->busy) {
-               module_put(w9968cf_vpp->owner);
-               w9968cf_vpp->busy--;
-               wake_up(&w9968cf_vppmod_wait);
-               DBG(5, "Video post-processing module released")
-       }
-
-       up(&w9968cf_vppmod_lock);
-}
-
-
-int w9968cf_vppmod_register(struct w9968cf_vpp_t* vpp)
-{
-       down(&w9968cf_vppmod_lock);
-
-       if (w9968cf_vpp) {
-               KDBG(1, "Video post-processing module already registered")
-               up(&w9968cf_vppmod_lock);
-               return -EINVAL;
-       }
-
-       w9968cf_vpp = vpp;
-       w9968cf_vpp->busy = 0;
-
-       KDBG(2, "Video post-processing module registered")
-       up(&w9968cf_vppmod_lock);
-       return 0;
-}
-
-
-int w9968cf_vppmod_deregister(struct w9968cf_vpp_t* vpp)
-{
-       down(&w9968cf_vppmod_lock);
-
-       if (!w9968cf_vpp) {
-               up(&w9968cf_vppmod_lock);
-               return -EINVAL;
-       }
-
-       if (w9968cf_vpp != vpp) {
-               KDBG(1, "Only the owner can unregister the video "
-                       "post-processing module")
-               up(&w9968cf_vppmod_lock);
-               return -EINVAL;
-       }
-
-       if (w9968cf_vpp->busy) {
-               KDBG(2, "Video post-processing module busy. Wait for it to be "
-                       "released...")
-               up(&w9968cf_vppmod_lock);
-               wait_event(w9968cf_vppmod_wait, !w9968cf_vpp->busy);
-               w9968cf_vpp = NULL;
-               goto out;
-       }
-
-       w9968cf_vpp = NULL;
-
-       up(&w9968cf_vppmod_lock);
-
-out:
-       KDBG(2, "Video post-processing module unregistered")
-       return 0;
-}
-
-
 static int __init w9968cf_module_init(void)
 {
        int err;
@@ -3810,6 +3687,3 @@ static void __exit w9968cf_module_exit(void)
 module_init(w9968cf_module_init);
 module_exit(w9968cf_module_exit);
 
-
-EXPORT_SYMBOL(w9968cf_vppmod_register);
-EXPORT_SYMBOL(w9968cf_vppmod_deregister);
index 8acbfe205bc760632397e9d1b32ab057129bb951..47a6ff7941712300dd492b2127b1b8243d47aa63 100644 (file)
@@ -195,7 +195,6 @@ enum w9968cf_vpp_flag {
 };
 
 static struct w9968cf_vpp_t* w9968cf_vpp;
-static DECLARE_MUTEX(w9968cf_vppmod_lock);
 static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
 
 static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
index 3f5317dc4c291522fee8ed8fd56e6749f5840bd3..f3b91b782671f4e6d14e12e8c67d80e2812800ea 100644 (file)
@@ -37,7 +37,4 @@ struct w9968cf_vpp_t {
        u8 busy; /* read-only flag: module is/is not in use */
 };
 
-extern int w9968cf_vppmod_register(struct w9968cf_vpp_t*);
-extern int w9968cf_vppmod_deregister(struct w9968cf_vpp_t*);
-
 #endif /* _W9968CF_VPP_H_ */
index 449b2501acf365ac0b105c0bfd4d15b0fa4bf8d5..ad2f4cccd3889d7a6b55dc973600000deb686cd7 100644 (file)
@@ -2093,6 +2093,8 @@ static void auerswald_disconnect (struct usb_interface *intf)
 static struct usb_device_id auerswald_ids [] = {
        { USB_DEVICE (ID_AUERSWALD, 0x00C0) },          /* COMpact 2104 USB */
        { USB_DEVICE (ID_AUERSWALD, 0x00DB) },          /* COMpact 4410/2206 USB */
+       { USB_DEVICE (ID_AUERSWALD, 0x00DC) }, /* COMpact 4406 DSL */
+       { USB_DEVICE (ID_AUERSWALD, 0x00DD) }, /* COMpact 2204 USB */
        { USB_DEVICE (ID_AUERSWALD, 0x00F1) },          /* Comfort 2000 System Telephone */
        { USB_DEVICE (ID_AUERSWALD, 0x00F2) },          /* Comfort 1200 System Telephone */
         { }                                            /* Terminating entry */
index 981d8a5fbfd9e9dd1a361e6939839d1cc629baaa..331d4ae949ed3ae175f39ecec2df72e2e72af125 100644 (file)
@@ -593,7 +593,7 @@ static struct file_operations ld_usb_fops = {
 
 /*
  * usb class driver info in order to get a minor number from the usb core,
- * and to have the device registered with devfs and the driver core
+ * and to have the device registered with the driver core
  */
 static struct usb_class_driver ld_usb_class = {
        .name =         "ldusb%d",
index 541181695040b865ec73fae31b2c8616c0875d38..3094970615cb9c8ce2aefd5013fc0181b2a230f8 100644 (file)
@@ -916,6 +916,10 @@ static const struct usb_device_id  products [] = {
        // Linksys USB200M Rev 2
        USB_DEVICE (0x13b1, 0x0018),
        .driver_info = (unsigned long) &ax88772_info,
+}, {
+       // 0Q0 cable ethernet
+       USB_DEVICE (0x1557, 0x7720),
+       .driver_info = (unsigned long) &ax88772_info,
 },
        { },            // END
 };
index da46b351e188eed017254eb28dad90fb4d0cb4fa..dc7a069503e04528eeb03dfae7b55237e6ead0eb 100644 (file)
@@ -32,7 +32,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.05"
+#define DRIVER_VERSION "v0.06"
 #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
 
 /*
@@ -55,11 +55,15 @@ static int debug;
 
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
-       { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
-       { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
-       { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
        { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
-       { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
+       { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
+       { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
+       { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
+       { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
+       { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
+       { 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(0x16D6, 0x0001) }, /* Jablotron serial interface */
        { } /* Terminating Entry */
 };
index 10bc1bf23b3514cb9bc50acad7c47f3dc3998583..f2b4ca8692d822c65bdc215a164fadd3d8bf9a73 100644 (file)
@@ -476,10 +476,16 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) },
        { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
        { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
        { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
index 00d45f8600deeccccfa398bd79606f9168ec6296..ca40f16370f1106bb612e0dd87af0b0401d8c3b9 100644 (file)
 #define FTDI_NF_RIC_VID        0x0DCD  /* Vendor Id */
 #define FTDI_NF_RIC_PID        0x0001  /* Product Id */
 
+
 /* www.irtrans.de device */
 #define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
 
+
+/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */
+#define FTDI_TTUSB_PID 0xFF20 /* Product Id */
+
 /* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */
 /* they use the ftdi chipset for the USB interface and the vendor id is the same */
 #define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */
 /* (the VID is the standard ftdi vid (FTDI_VID) */
 #define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */
 
+/*
+ * PCDJ use ftdi based dj-controllers.  The following PID is for their DAC-2 device
+ * http://www.pcdjhardware.com/DAC2.asp (PID sent by Wouter Paesen)
+ * (the VID is the standard ftdi vid (FTDI_VID) */
+#define FTDI_PCDJ_DAC2_PID 0xFA88
+
 /*
  * The following are the values for the Matrix Orbital LCD displays,
  * which are the FT232BM ( similar to the 8U232AM )
  * Definitions for ATIK Instruments astronomical USB based cameras
  * Check it at http://www.atik-instruments.com/
  */
-#define FTDI_ATIK_ATK16_PID    0xDF30  /* ATIK ATK-16 Camera */
-#define FTDI_ATIK_ATK16HR_PID  0xDF31  /* ATIK ATK-16HR Camera */
+#define FTDI_ATIK_ATK16_PID    0xDF30  /* ATIK ATK-16 Grayscale Camera */
+#define FTDI_ATIK_ATK16C_PID   0xDF32  /* ATIK ATK-16C Colour Camera */
+#define FTDI_ATIK_ATK16HR_PID  0xDF31  /* ATIK ATK-16HR Grayscale Camera */
+#define FTDI_ATIK_ATK16HRC_PID 0xDF33  /* ATIK ATK-16HRC Colour Camera */
 
 /*
  * Protego product ids
 #define POSIFLEX_VID           0x0d3a  /* Vendor ID */
 #define POSIFLEX_PP7000_PID    0x0300  /* PP-7000II thermal printer */
 
+/*
+ * Westrex International devices submitted by Cory Lee
+ */
+#define FTDI_WESTREX_MODEL_777_PID     0xDC00  /* Model 777 */
+#define FTDI_WESTREX_MODEL_8900F_PID   0xDC01  /* Model 8900F */
+
 /* Commands */
 #define FTDI_SIO_RESET                 0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL    1 /* Set the modem control register */
index 0eb883f44adaee3bfde6c2879ca63a7e98ae668a..e8e575e037c11352b1d1fc65c51192167ec3c74e 100644 (file)
@@ -73,7 +73,9 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
        { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
-       { USB_DEVICE( NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID ) },
+       { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID ) },
+       { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID ) },
+       { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
 
index 21d434d81813dde3c207d778ecb7067944092e43..1807087a76e3dbe0f218b73c873b172100ab79d4 100644 (file)
 /* Nokia CA-42 Cable */
 #define NOKIA_CA42_VENDOR_ID   0x078b
 #define NOKIA_CA42_PRODUCT_ID  0x1234
+
+/* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */
+#define CA_42_CA42_VENDOR_ID   0x10b5
+#define CA_42_CA42_PRODUCT_ID  0xac70
+
+#define SAGEM_VENDOR_ID                0x079b
+#define SAGEM_PRODUCT_ID       0x0027
index 5b06f9240d05caa2b348c7cf55cf520ff2ca2240..ab173b30076eb1b7ac2ec3a2fe257a78863918d5 100644 (file)
 #include "debug.h"
 #include "transport.h"
 
+#define RIO_MSC 0x08
+#define RIOP_INIT "RIOP\x00\x01\x08"
+#define RIOP_INIT_LEN 7
+#define RIO_SEND_LEN 40
+#define RIO_RECV_LEN 0x200
+
 /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
  * mode */
 int usb_stor_euscsi_init(struct us_data *us)
@@ -91,3 +97,70 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
 
        return (res ? -1 : 0);
 }
+
+/* Place the Rio Karma into mass storage mode.
+ *
+ * The initialization begins by sending 40 bytes starting
+ * RIOP\x00\x01\x08\x00, which the device will ack with a 512-byte
+ * packet with the high four bits set and everything else null.
+ *
+ * Next, we send RIOP\x80\x00\x08\x00.  Each time, a 512 byte response
+ * must be read, but we must loop until byte 5 in the response is 0x08,
+ * indicating success.  */
+int rio_karma_init(struct us_data *us)
+{
+       int result, partial;
+       char *recv;
+       unsigned long timeout;
+
+       // us->iobuf is big enough to hold cmd but not receive
+       if (!(recv = kmalloc(RIO_RECV_LEN, GFP_KERNEL)))
+               goto die_nomem;
+
+       US_DEBUGP("Initializing Karma...\n");
+
+       memset(us->iobuf, 0, RIO_SEND_LEN);
+       memcpy(us->iobuf, RIOP_INIT, RIOP_INIT_LEN);
+
+       result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+               us->iobuf, RIO_SEND_LEN, &partial);
+       if (result != USB_STOR_XFER_GOOD)
+               goto die;
+
+       result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+               recv, RIO_RECV_LEN, &partial);
+       if (result != USB_STOR_XFER_GOOD)
+               goto die;
+
+       us->iobuf[4] = 0x80;
+       us->iobuf[5] = 0;
+       timeout = jiffies + msecs_to_jiffies(3000);
+       for (;;) {
+               US_DEBUGP("Sending init command\n");
+               result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+                       us->iobuf, RIO_SEND_LEN, &partial);
+               if (result != USB_STOR_XFER_GOOD)
+                       goto die;
+
+               result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+                       recv, RIO_RECV_LEN, &partial);
+               if (result != USB_STOR_XFER_GOOD)
+                       goto die;
+
+               if (recv[5] == RIO_MSC)
+                       break;
+               if (time_after(jiffies, timeout))
+                       goto die;
+               msleep(10);
+       }
+       US_DEBUGP("Karma initialized.\n");
+       kfree(recv);
+       return 0;
+
+die:
+       kfree(recv);
+die_nomem:
+       US_DEBUGP("Could not initialize karma.\n");
+       return USB_STOR_TRANSPORT_FAILED;
+}
+
index 4c1b2bd2e2e41edcc0378b2a8b8aadf90efe7319..f9907a5cf129f42057d590bd7ca3c6551533599d 100644 (file)
@@ -48,3 +48,4 @@ int usb_stor_euscsi_init(struct us_data *us);
 /* This function is required to activate all four slots on the UCR-61S2B
  * flash reader */
 int usb_stor_ucr61s2b_init(struct us_data *us);
+int rio_karma_init(struct us_data *us);
index b28151d1b609b9ba3554c6625f7662a0c16b2808..b1ec4a718547316c62cf39fa4872ffd7651424f9 100644 (file)
@@ -116,7 +116,7 @@ EXPORT_SYMBOL_GPL(usb_usual_check_type);
 static int usu_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
-       int type;
+       unsigned long type;
        int rc;
        unsigned long flags;
 
index dc301e567cfc6c6ec5037b7ff26246d72276e09b..ee958f986eb8a37c86422b837906f71d4fd1f508 100644 (file)
@@ -145,6 +145,11 @@ UNUSUAL_DEV(  0x0451, 0x5416, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_BULK, NULL,
                US_FL_NEED_OVERRIDE ),
 
+UNUSUAL_DEV(  0x045a, 0x5210, 0x0101, 0x0101,
+               "Rio",
+               "Rio Karma",
+               US_SC_SCSI, US_PR_BULK, rio_karma_init, 0),
+
 /* Patch submitted by Philipp Friedrich <philipp@void.at> */
 UNUSUAL_DEV(  0x0482, 0x0100, 0x0100, 0x0100,
                "Kyocera",
@@ -424,11 +429,11 @@ UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0450,
                US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ),
 
 /* This entry is needed because the device reports Sub=ff */
-UNUSUAL_DEV(  0x054c, 0x0010, 0x0500, 0x0500, 
-               "Sony",
-               "DSC-T1", 
-               US_SC_8070, US_PR_DEVICE, NULL,
-               US_FL_SINGLE_LUN ),
+UNUSUAL_DEV(  0x054c, 0x0010, 0x0500, 0x0600,
+               "Sony",
+               "DSC-T1/T5",
+               US_SC_8070, US_PR_DEVICE, NULL,
+               US_FL_SINGLE_LUN ),
 
 
 /* Reported by wim@geeks.nl */
index 5d02f16b7d0e7b007720486d7f2722b37f58f85e..4de9fb56ebfc02294636e65b1ca92303286e2b4e 100644 (file)
@@ -234,7 +234,7 @@ static struct file_operations skel_fops = {
 
 /* 
  * usb class driver info in order to get a minor number from the usb core,
- * and to have the device registered with devfs and the driver core
+ * and to have the device registered with the driver core
  */
 static struct usb_class_driver skel_class = {
        .name =         "skel%d",
index b2187175d03fcde37c6daa66f240b0cdb36c4a71..6761b68c35e97182046e1774d1755ef810423bb7 100644 (file)
@@ -116,9 +116,10 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
        int ret = 0;
 
        memset(&var->transp, 0, sizeof(var->transp));
-       memset(&var->red, 0, sizeof(var->red));
-       memset(&var->green, 0, sizeof(var->green));
-       memset(&var->blue, 0, sizeof(var->blue));
+
+       var->red.msb_right = 0;
+       var->green.msb_right = 0;
+       var->blue.msb_right = 0;
 
        switch (var->bits_per_pixel) {
        case 1:
@@ -133,34 +134,20 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
                var->blue.offset        = 0;
                break;
        case 16:
-               var->red.length         = 5;
-               var->green.length       = 6;
-               var->blue.length        = 5;
-               if (fb->panel->cntl & CNTL_BGR) {
-                       var->red.offset         = 11;
-                       var->green.offset       = 5;
-                       var->blue.offset        = 0;
-               } else {
-                       var->red.offset         = 0;
-                       var->green.offset       = 5;
-                       var->blue.offset        = 11;
-               }
+               var->red.length = 5;
+               var->blue.length = 5;
+               /*
+                * Green length can be 5 or 6 depending whether
+                * we're operating in RGB555 or RGB565 mode.
+                */
+               if (var->green.length != 5 && var->green.length != 6)
+                       var->green.length = 6;
                break;
        case 32:
                if (fb->panel->cntl & CNTL_LCDTFT) {
                        var->red.length         = 8;
                        var->green.length       = 8;
                        var->blue.length        = 8;
-
-                       if (fb->panel->cntl & CNTL_BGR) {
-                               var->red.offset         = 16;
-                               var->green.offset       = 8;
-                               var->blue.offset        = 0;
-                       } else {
-                               var->red.offset         = 0;
-                               var->green.offset       = 8;
-                               var->blue.offset        = 16;
-                       }
                        break;
                }
        default:
@@ -168,6 +155,23 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
                break;
        }
 
+       /*
+        * >= 16bpp displays have separate colour component bitfields
+        * encoded in the pixel data.  Calculate their position from
+        * the bitfield length defined above.
+        */
+       if (ret == 0 && var->bits_per_pixel >= 16) {
+               if (fb->panel->cntl & CNTL_BGR) {
+                       var->blue.offset = 0;
+                       var->green.offset = var->blue.offset + var->blue.length;
+                       var->red.offset = var->green.offset + var->green.length;
+               } else {
+                       var->red.offset = 0;
+                       var->green.offset = var->red.offset + var->red.length;
+                       var->blue.offset = var->green.offset + var->green.length;
+               }
+       }
+
        return ret;
 }
 
index 2b972461a030b9f2cfa92ee4aea4a62fa2c8b56e..0ae0a97b0fed05c5ea8129b018d2179eecac87bc 100644 (file)
@@ -1665,7 +1665,6 @@ static int __devinit cyblafb_init(void)
                }
 #endif
        output("CyblaFB version %s initializing\n", VERSION);
-       return pci_module_init(&cyblafb_pci_driver);
        return pci_register_driver(&cyblafb_pci_driver);
 }
 
index bbc442b8c86722dbe69651fb593bfe7d3f6c936c..1f3bb501c262bc9b94ad9e0b73c5af8acc511c90 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -411,6 +411,7 @@ static int __bio_add_page(request_queue_t *q, struct bio *bio, struct page
 
 /**
  *     bio_add_pc_page -       attempt to add page to bio
+ *     @q: the target queue
  *     @bio: destination bio
  *     @page: page to add
  *     @len: vec entry length
index abfbe45cd17c9ff5c64b2e871bd00cc2682eb309..5f8223e700d353f22a75c94c3e173f14ad609b78 100644 (file)
@@ -25,7 +25,7 @@
                .macro addruart, rx
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1
-               ldreq   \rx, = S3C2410_PA_UART
+               ldreq   \rx, = S3C24XX_PA_UART
                ldrne   \rx, = S3C24XX_VA_UART
 #if CONFIG_DEBUG_S3C2410_UART != 0
                add     \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C2410_UART)
@@ -44,7 +44,7 @@
 1003:
                mrc     p15, 0, \rd, c1, c0
                tst     \rd, #1
-               addeq   \rd, \rx, #(S3C2410_PA_GPIO - S3C2410_PA_UART)
+               addeq   \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
                addne   \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART)
                bic     \rd, \rd, #0xff000
                ldr     \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
@@ -75,7 +75,7 @@
 1003:
                mrc     p15, 0, \rd, c1, c0
                tst     \rd, #1
-               addeq   \rd, \rx, #(S3C2410_PA_GPIO - S3C2410_PA_UART)
+               addeq   \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
                addne   \rd, \rx, #(S3C24XX_VA_GPIO - S3C24XX_VA_UART)
                bic     \rd, \rd, #0xff000
                ldr     \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ]
index 1833ea5c4220b34d2594189e61caa4ab444ca84d..c380d264a8479137fe2a979b91d9969fc64cac03 100644 (file)
@@ -14,6 +14,7 @@
  *  06-Jan-2003 BJD   Linux 2.6.0 version, moved bast specifics out
  *  10-Feb-2005 BJD   Added CAMIF definition from guillaume.gourat@nexvision.tv
  *  10-Mar-2005 LCVR  Added support to S3C2400, changed {VA,SZ} names
+ *  15-Jan-2006 LCVR  Added S3C24XX_PA macros for common S3C24XX resources
 */
 
 #ifndef __ASM_ARCH_MAP_H
 
 #define S3C2400_SDRAM_PA    (S3C2400_CS6)
 
+/* Use a single interface for common resources between S3C24XX cpus */
+
+#ifdef CONFIG_CPU_S3C2400
+#define S3C24XX_PA_IRQ      S3C2400_PA_IRQ
+#define S3C24XX_PA_MEMCTRL  S3C2400_PA_MEMCTRL
+#define S3C24XX_PA_USBHOST  S3C2400_PA_USBHOST
+#define S3C24XX_PA_DMA      S3C2400_PA_DMA
+#define S3C24XX_PA_CLKPWR   S3C2400_PA_CLKPWR
+#define S3C24XX_PA_LCD      S3C2400_PA_LCD
+#define S3C24XX_PA_UART     S3C2400_PA_UART
+#define S3C24XX_PA_TIMER    S3C2400_PA_TIMER
+#define S3C24XX_PA_USBDEV   S3C2400_PA_USBDEV
+#define S3C24XX_PA_WATCHDOG S3C2400_PA_WATCHDOG
+#define S3C24XX_PA_IIC      S3C2400_PA_IIC
+#define S3C24XX_PA_IIS      S3C2400_PA_IIS
+#define S3C24XX_PA_GPIO     S3C2400_PA_GPIO
+#define S3C24XX_PA_RTC      S3C2400_PA_RTC
+#define S3C24XX_PA_ADC      S3C2400_PA_ADC
+#define S3C24XX_PA_SPI      S3C2400_PA_SPI
+#else
+#define S3C24XX_PA_IRQ      S3C2410_PA_IRQ
+#define S3C24XX_PA_MEMCTRL  S3C2410_PA_MEMCTRL
+#define S3C24XX_PA_USBHOST  S3C2410_PA_USBHOST
+#define S3C24XX_PA_DMA      S3C2410_PA_DMA
+#define S3C24XX_PA_CLKPWR   S3C2410_PA_CLKPWR
+#define S3C24XX_PA_LCD      S3C2410_PA_LCD
+#define S3C24XX_PA_UART     S3C2410_PA_UART
+#define S3C24XX_PA_TIMER    S3C2410_PA_TIMER
+#define S3C24XX_PA_USBDEV   S3C2410_PA_USBDEV
+#define S3C24XX_PA_WATCHDOG S3C2410_PA_WATCHDOG
+#define S3C24XX_PA_IIC      S3C2410_PA_IIC
+#define S3C24XX_PA_IIS      S3C2410_PA_IIS
+#define S3C24XX_PA_GPIO     S3C2410_PA_GPIO
+#define S3C24XX_PA_RTC      S3C2410_PA_RTC
+#define S3C24XX_PA_ADC      S3C2410_PA_ADC
+#define S3C24XX_PA_SPI      S3C2410_PA_SPI
+#endif
 
 #endif /* __ASM_ARCH_MAP_H */
index ce1bbbaad6d36a6876fdb2534ebfb2103970b90b..83b01254c4ac7374421cbad670debe9424ef42cc 100644 (file)
@@ -39,9 +39,9 @@
 #define S3C24XX_VA_UART1      (S3C24XX_VA_UART + 0x4000 )
 #define S3C24XX_VA_UART2      (S3C24XX_VA_UART + 0x8000 )
 
-#define S3C2410_PA_UART0      (S3C2410_PA_UART)
-#define S3C2410_PA_UART1      (S3C2410_PA_UART + 0x4000 )
-#define S3C2410_PA_UART2      (S3C2410_PA_UART + 0x8000 )
+#define S3C2410_PA_UART0      (S3C24XX_PA_UART)
+#define S3C2410_PA_UART1      (S3C24XX_PA_UART + 0x4000 )
+#define S3C2410_PA_UART2      (S3C24XX_PA_UART + 0x8000 )
 
 #define S3C2410_URXH     (0x24)
 #define S3C2410_UTXH     (0x20)
index ddd1578a7ee0a40d2877434176f7718797c9b1a4..4367ec054b51aeb277040bbee9c5f47bb99b5762 100644 (file)
 #undef S3C2410_GPIOREG
 #undef S3C2410_WDOGREG
 
-#define S3C2410_GPIOREG(x) ((S3C2410_PA_GPIO + (x)))
-#define S3C2410_WDOGREG(x) ((S3C2410_PA_WATCHDOG + (x)))
+#define S3C2410_GPIOREG(x) ((S3C24XX_PA_GPIO + (x)))
+#define S3C2410_WDOGREG(x) ((S3C24XX_PA_WATCHDOG + (x)))
 
 /* how many bytes we allow into the FIFO at a time in FIFO mode */
 #define FIFO_MAX        (14)
 
-#define uart_base S3C2410_PA_UART + (0x4000*CONFIG_S3C2410_LOWLEVEL_UART_PORT)
+#define uart_base S3C24XX_PA_UART + (0x4000*CONFIG_S3C2410_LOWLEVEL_UART_PORT)
 
 static __inline__ void
 uart_wr(unsigned int reg, unsigned int val)
index 3351b77fab36e93bc86ef94c74a45a7b6b4295a4..e8ea67c97c73d3526b3c7025dbc9a468e1ef6331 100644 (file)
@@ -26,6 +26,7 @@ struct meminfo;
 #define MT_MEMORY              5
 #define MT_ROM                 6
 #define MT_IXP2000_DEVICE      7
+#define MT_NONSHARED_DEVICE    8
 
 extern void create_memmap_holes(struct meminfo *);
 extern void memtable_init(struct meminfo *);
index 5a0d19b466b0cd2242bbf6f1fca244ec90d12617..70e00d08345ec93d6b989fc47b2a5099272375d6 100644 (file)
@@ -168,6 +168,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
 #define PMD_SECT_WB            (PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE)
 #define PMD_SECT_MINICACHE     (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE)
 #define PMD_SECT_WBWA          (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE)
+#define PMD_SECT_NONSHARED_DEV (PMD_SECT_TEX(2))
 
 /*
  *   - coarse table (not used)
index e68a80853d5dfaf81beb54d45727e495ba8f013e..9ca642cad33878a0a3de28c74ae639998099ea86 100644 (file)
@@ -8,7 +8,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2005 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2005-2006 Silicon Graphics, Inc.  All rights reserved.
  */
 
 
@@ -27,14 +27,12 @@ extern int sn_prom_feature_available(int id);
  * "false" for new features.
  *
  * Use:
- *             if (sn_prom_feature_available(PRF_FEATURE_XXX))
+ *             if (sn_prom_feature_available(PRF_XXX))
  *                     ...
  */
 
-/*
- * Example: feature XXX
- */
-#define PRF_FEATURE_XXX                0
+#define PRF_PAL_CACHE_FLUSH_SAFE       0
+#define PRF_DEVICE_FLUSH_LIST          1
 
 
 
@@ -51,7 +49,7 @@ extern int sn_prom_feature_available(int id);
  *
  * By default, features are disabled unless explicitly enabled.
  */
-#define  OSF_MCA_SLV_TO_OS_INIT_SLV            0
-#define  OSF_FEAT_LOG_SBES                     1
+#define  OSF_MCA_SLV_TO_OS_INIT_SLV    0
+#define  OSF_FEAT_LOG_SBES             1
 
 #endif /* _ASM_IA64_SN_FEATURE_SETS_H */
index ec85d12d73b98a353e0fdcaf346489b09f80839a..508c416e9d6a8b1423ab3bb88eef8ee27d67ec9a 100644 (file)
@@ -131,6 +131,28 @@ static void inline __read_lock(raw_rwlock_t *lock)
        : "memory");
 }
 
+static int inline __read_trylock(raw_rwlock_t *lock)
+{
+       int tmp1, tmp2;
+
+       __asm__ __volatile__ (
+"1:    ldsw            [%2], %0\n"
+"      brlz,a,pn       %0, 2f\n"
+"       mov            0, %0\n"
+"      add             %0, 1, %1\n"
+"      cas             [%2], %0, %1\n"
+"      cmp             %0, %1\n"
+"      membar          #StoreLoad | #StoreStore\n"
+"      bne,pn          %%icc, 1b\n"
+"       mov            1, %0\n"
+"2:"
+       : "=&r" (tmp1), "=&r" (tmp2)
+       : "r" (lock)
+       : "memory");
+
+       return tmp1;
+}
+
 static void inline __read_unlock(raw_rwlock_t *lock)
 {
        unsigned long tmp1, tmp2;
@@ -211,12 +233,12 @@ static int inline __write_trylock(raw_rwlock_t *lock)
 }
 
 #define __raw_read_lock(p)     __read_lock(p)
+#define __raw_read_trylock(p)  __read_trylock(p)
 #define __raw_read_unlock(p)   __read_unlock(p)
 #define __raw_write_lock(p)    __write_lock(p)
 #define __raw_write_unlock(p)  __write_unlock(p)
 #define __raw_write_trylock(p) __write_trylock(p)
 
-#define __raw_read_trylock(lock)       generic__raw_read_trylock(lock)
 #define __raw_read_can_lock(rw)                (!((rw)->lock & 0x80000000UL))
 #define __raw_write_can_lock(rw)       (!(rw)->lock)
 
index 17a17c55a17f97c2da02e7b83f1ca367f7bc6d5e..6d59c8efe3be2a1be4b1bb559bb506c551d3c213 100644 (file)
@@ -111,6 +111,7 @@ typedef struct _agp_unbind {
 } agp_unbind;
 
 #else                          /* __KERNEL__ */
+#include <linux/mutex.h>
 
 #define AGPGART_MINOR 175
 
@@ -201,7 +202,7 @@ struct agp_file_private {
 };
 
 struct agp_front_data {
-       struct semaphore agp_mutex;
+       struct mutex agp_mutex;
        struct agp_controller *current_controller;
        struct agp_controller *controllers;
        struct agp_file_private *file_priv_list;
index 02a585faa62cfd689510b943717cc6f79101184b..860e7a485a5f08d2aaa10129d65c6339c128a008 100644 (file)
@@ -392,8 +392,8 @@ struct request_queue
        unsigned int            nr_congestion_off;
        unsigned int            nr_batching;
 
-       unsigned short          max_sectors;
-       unsigned short          max_hw_sectors;
+       unsigned int            max_sectors;
+       unsigned int            max_hw_sectors;
        unsigned short          max_phys_segments;
        unsigned short          max_hw_segments;
        unsigned short          hardsect_size;
@@ -697,7 +697,7 @@ extern request_queue_t *blk_init_queue(request_fn_proc *, spinlock_t *);
 extern void blk_cleanup_queue(request_queue_t *);
 extern void blk_queue_make_request(request_queue_t *, make_request_fn *);
 extern void blk_queue_bounce_limit(request_queue_t *, u64);
-extern void blk_queue_max_sectors(request_queue_t *, unsigned short);
+extern void blk_queue_max_sectors(request_queue_t *, unsigned int);
 extern void blk_queue_max_phys_segments(request_queue_t *, unsigned short);
 extern void blk_queue_max_hw_segments(request_queue_t *, unsigned short);
 extern void blk_queue_max_segment_size(request_queue_t *, unsigned int);
index c31650df92412de9c6514e81bc5955e8f8a02dcb..17866d7e2b71ad08e12fc9340d5b77448032da48 100644 (file)
@@ -14,6 +14,7 @@
 #ifndef _LINUX_CPUFREQ_H
 #define _LINUX_CPUFREQ_H
 
+#include <linux/mutex.h>
 #include <linux/config.h>
 #include <linux/notifier.h>
 #include <linux/threads.h>
@@ -82,7 +83,7 @@ struct cpufreq_policy {
         unsigned int           policy; /* see above */
        struct cpufreq_governor *governor; /* see below */
 
-       struct semaphore        lock;   /* CPU ->setpolicy or ->target may
+       struct mutex            lock;   /* CPU ->setpolicy or ->target may
                                           only be called once a time */
 
        struct work_struct      update; /* if update_policy() needs to be
index 59ff6c430cf6eb1e8609acf7abecfd347c54e512..6500d4e59d46c5c6f60bfba239aad63f4639b7bf 100644 (file)
@@ -19,7 +19,21 @@ struct xt_get_revision
 /* For standard target */
 #define XT_RETURN (-NF_REPEAT - 1)
 
-#define XT_ALIGN(s) (((s) + (__alignof__(u_int64_t)-1)) & ~(__alignof__(u_int64_t)-1))
+/* this is a dummy structure to find out the alignment requirement for a struct
+ * containing all the fundamental data types that are used in ipt_entry,
+ * ip6t_entry and arpt_entry.  This sucks, and it is a hack.  It will be my
+ * personal pleasure to remove it -HW
+ */
+struct _xt_align
+{
+       u_int8_t u8;
+       u_int16_t u16;
+       u_int32_t u32;
+       u_int64_t u64;
+};
+
+#define XT_ALIGN(s) (((s) + (__alignof__(struct _xt_align)-1))         \
+                       & ~(__alignof__(struct _xt_align)-1))
 
 /* Standard return verdict, or do jump. */
 #define XT_STANDARD_TARGET ""
index 0a44072383ec417647194cc505fb5e4d19447302..fe1a2b02fc558d158182642b979d0f6159aceb18 100644 (file)
@@ -406,7 +406,6 @@ struct pci_dev *pci_find_device_reverse (unsigned int vendor, unsigned int devic
 struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
 int pci_find_capability (struct pci_dev *dev, int cap);
 int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
-int pci_find_ext_capability (struct pci_dev *dev, int cap);
 struct pci_bus * pci_find_next_bus(const struct pci_bus *from);
 
 struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
@@ -626,7 +625,6 @@ static inline int pci_register_driver(struct pci_driver *drv) { return 0;}
 static inline void pci_unregister_driver(struct pci_driver *drv) { }
 static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; }
 static inline int pci_find_next_capability (struct pci_dev *dev, u8 post, int cap) { return 0; }
-static inline int pci_find_ext_capability (struct pci_dev *dev, int cap) {return 0; }
 static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; }
 
 /* Power management related routines */
index ecc1fc1f0f0442f644269f921ac8563ea8c92642..b0b908f583c58a38a614e6e51f30d71ae43d9508 100644 (file)
 #define PCI_DEVICE_ID_NS_SC1100_SMI    0x0511
 #define PCI_DEVICE_ID_NS_SC1100_XBUS   0x0515
 #define PCI_DEVICE_ID_NS_87410         0xd001
-#define PCI_DEVICE_ID_NS_CS5535_IDE    0x002d
 
 #define PCI_DEVICE_ID_NS_CS5535_HOST_BRIDGE  0x0028
 #define PCI_DEVICE_ID_NS_CS5535_ISA_BRIDGE   0x002b
-#define PCI_DEVICE_ID_NS_CS5535_IDE          0x002d
-#define PCI_DEVICE_ID_NS_CS5535_AUDIO        0x002e
-#define PCI_DEVICE_ID_NS_CS5535_USB          0x002f
-#define PCI_DEVICE_ID_NS_CS5535_VIDEO        0x0030
 
 #define PCI_VENDOR_ID_TSENG            0x100c
 #define PCI_DEVICE_ID_TSENG_W32P_2     0x3202
 #define PCI_DEVICE_ID_AMD_CS5536_UOC    0x2097
 #define PCI_DEVICE_ID_AMD_CS5536_IDE    0x209A
 
-#define PCI_DEVICE_ID_AMD_CS5536_IDE   0x209A
-
 #define PCI_DEVICE_ID_AMD_LX_VIDEO  0x2081
 #define PCI_DEVICE_ID_AMD_LX_AES    0x2082
 
 #define PCI_DEVICE_ID_INTEL_82801EB_5  0x24d5
 #define PCI_DEVICE_ID_INTEL_82801EB_6  0x24d6
 #define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db
+#define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd
 #define PCI_DEVICE_ID_INTEL_ESB_1      0x25a1
 #define PCI_DEVICE_ID_INTEL_ESB_2      0x25a2
 #define PCI_DEVICE_ID_INTEL_ESB_4      0x25a4
 #define PCI_DEVICE_ID_INTEL_82915GM_IG 0x2592
 #define PCI_DEVICE_ID_INTEL_82945G_HB  0x2770
 #define PCI_DEVICE_ID_INTEL_82945G_IG  0x2772
+#define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27A0
+#define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27A2
 #define PCI_DEVICE_ID_INTEL_ICH6_0     0x2640
 #define PCI_DEVICE_ID_INTEL_ICH6_1     0x2641
 #define PCI_DEVICE_ID_INTEL_ICH6_2     0x2642
 #define PCI_DEVICE_ID_INTEL_ICH7_19    0x27dd
 #define PCI_DEVICE_ID_INTEL_ICH7_20    0x27de
 #define PCI_DEVICE_ID_INTEL_ICH7_21    0x27df
+#define PCI_DEVICE_ID_INTEL_ICH8_0     0x2810
+#define PCI_DEVICE_ID_INTEL_ICH8_1     0x2811
+#define PCI_DEVICE_ID_INTEL_ICH8_2     0x2812
+#define PCI_DEVICE_ID_INTEL_ICH8_3     0x2814
+#define PCI_DEVICE_ID_INTEL_ICH8_4     0x2815
+#define PCI_DEVICE_ID_INTEL_ICH8_5     0x283e
+#define PCI_DEVICE_ID_INTEL_ICH8_6     0x2850
 #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340
 #define PCI_DEVICE_ID_INTEL_82830_HB   0x3575
 #define PCI_DEVICE_ID_INTEL_82830_CGC  0x3577
 #define PCI_DEVICE_ID_INTEL_82443GX_2  0x71a2
 #define PCI_DEVICE_ID_INTEL_82372FB_1  0x7601
 #define PCI_DEVICE_ID_INTEL_82454GX    0x84c4
+#define PCI_DEVICE_ID_INTEL_82450GX    0x84c5
 #define PCI_DEVICE_ID_INTEL_82451NX    0x84ca
 #define PCI_DEVICE_ID_INTEL_82454NX     0x84cb
 #define PCI_DEVICE_ID_INTEL_84460GX    0x84ea
index cee302aefdb71b3efcbd8027af9a68b79189ddee..73b464f0926a861438c73cbcf27e996a9ccabf0f 100644 (file)
@@ -26,7 +26,7 @@ struct plat_serial8250_port {
        unsigned char   regshift;       /* register shift */
        unsigned char   iotype;         /* UPIO_* */
        unsigned char   hub6;
-       unsigned int    flags;          /* UPF_* flags */
+       upf_t           flags;          /* UPF_* flags */
 };
 
 /*
index ec351005bf9d9ccb5c521a9048dfdcad7c2db57b..4041122dabfcf66cd2eca416a227569f474b5c84 100644 (file)
@@ -203,6 +203,8 @@ struct uart_icount {
        __u32   buf_overrun;
 };
 
+typedef unsigned int __bitwise__ upf_t;
+
 struct uart_port {
        spinlock_t              lock;                   /* port lock */
        unsigned int            iobase;                 /* in/out[bwl] */
@@ -230,36 +232,34 @@ struct uart_port {
        unsigned long           sysrq;                  /* sysrq timeout */
 #endif
 
-       unsigned int            flags;
-
-#define UPF_FOURPORT           (1 << 1)
-#define UPF_SAK                        (1 << 2)
-#define UPF_SPD_MASK           (0x1030)
-#define UPF_SPD_HI             (0x0010)
-#define UPF_SPD_VHI            (0x0020)
-#define UPF_SPD_CUST           (0x0030)
-#define UPF_SPD_SHI            (0x1000)
-#define UPF_SPD_WARP           (0x1010)
-#define UPF_SKIP_TEST          (1 << 6)
-#define UPF_AUTO_IRQ           (1 << 7)
-#define UPF_HARDPPS_CD         (1 << 11)
-#define UPF_LOW_LATENCY                (1 << 13)
-#define UPF_BUGGY_UART         (1 << 14)
-#define UPF_AUTOPROBE          (1 << 15)
-#define UPF_MAGIC_MULTIPLIER   (1 << 16)
-#define UPF_BOOT_ONLYMCA       (1 << 22)
-#define UPF_CONS_FLOW          (1 << 23)
-#define UPF_SHARE_IRQ          (1 << 24)
-#define UPF_BOOT_AUTOCONF      (1 << 28)
-#define UPF_IOREMAP            (1 << 31)
-
-#define UPF_CHANGE_MASK                (0x17fff)
-#define UPF_USR_MASK           (UPF_SPD_MASK|UPF_LOW_LATENCY)
+       upf_t                   flags;
+
+#define UPF_FOURPORT           ((__force upf_t) (1 << 1))
+#define UPF_SAK                        ((__force upf_t) (1 << 2))
+#define UPF_SPD_MASK           ((__force upf_t) (0x1030))
+#define UPF_SPD_HI             ((__force upf_t) (0x0010))
+#define UPF_SPD_VHI            ((__force upf_t) (0x0020))
+#define UPF_SPD_CUST           ((__force upf_t) (0x0030))
+#define UPF_SPD_SHI            ((__force upf_t) (0x1000))
+#define UPF_SPD_WARP           ((__force upf_t) (0x1010))
+#define UPF_SKIP_TEST          ((__force upf_t) (1 << 6))
+#define UPF_AUTO_IRQ           ((__force upf_t) (1 << 7))
+#define UPF_HARDPPS_CD         ((__force upf_t) (1 << 11))
+#define UPF_LOW_LATENCY                ((__force upf_t) (1 << 13))
+#define UPF_BUGGY_UART         ((__force upf_t) (1 << 14))
+#define UPF_MAGIC_MULTIPLIER   ((__force upf_t) (1 << 16))
+#define UPF_CONS_FLOW          ((__force upf_t) (1 << 23))
+#define UPF_SHARE_IRQ          ((__force upf_t) (1 << 24))
+#define UPF_BOOT_AUTOCONF      ((__force upf_t) (1 << 28))
+#define UPF_IOREMAP            ((__force upf_t) (1 << 31))
+
+#define UPF_CHANGE_MASK                ((__force upf_t) (0x17fff))
+#define UPF_USR_MASK           ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
 
        unsigned int            mctrl;                  /* current modem ctrl settings */
        unsigned int            timeout;                /* character-based timeout */
        unsigned int            type;                   /* port type */
-       struct uart_ops         *ops;
+       const struct uart_ops   *ops;
        unsigned int            custom_divisor;
        unsigned int            line;                   /* port index */
        unsigned long           mapbase;                /* for ioremap */
@@ -289,6 +289,9 @@ struct uart_state {
 };
 
 #define UART_XMIT_SIZE PAGE_SIZE
+
+typedef unsigned int __bitwise__ uif_t;
+
 /*
  * This is the state information which is only valid when the port
  * is open; it may be freed by the core driver once the device has
@@ -298,17 +301,16 @@ struct uart_state {
 struct uart_info {
        struct tty_struct       *tty;
        struct circ_buf         xmit;
-       unsigned int            flags;
+       uif_t                   flags;
 
 /*
- * These are the flags that specific to info->flags, and reflect our
- * internal state.  They can not be accessed via port->flags.  Low
- * level drivers must not change these, but may query them instead.
+ * Definitions for info->flags.  These are _private_ to serial_core, and
+ * are specific to this structure.  They may be queried by low level drivers.
  */
-#define UIF_CHECK_CD           (1 << 25)
-#define UIF_CTS_FLOW           (1 << 26)
-#define UIF_NORMAL_ACTIVE      (1 << 29)
-#define UIF_INITIALIZED                (1 << 31)
+#define UIF_CHECK_CD           ((__force uif_t) (1 << 25))
+#define UIF_CTS_FLOW           ((__force uif_t) (1 << 26))
+#define UIF_NORMAL_ACTIVE      ((__force uif_t) (1 << 29))
+#define UIF_INITIALIZED                ((__force uif_t) (1 << 31))
 
        int                     blocked_open;
 
@@ -430,7 +432,7 @@ static inline int uart_handle_break(struct uart_port *port)
                port->sysrq = 0;
        }
 #endif
-       if (info->flags & UPF_SAK)
+       if (port->flags & UPF_SAK)
                do_SAK(info->tty);
        return 0;
 }
index ee21e6bf3867a8bff6d2ac30a32ce6f4743a9536..a2aacfc7af2f968ac6b16cb0fc31845f97dcd4d9 100644 (file)
@@ -535,9 +535,11 @@ enum usb_device_state {
         */
        USB_STATE_NOTATTACHED = 0,
 
-       /* the chapter 9 device states */
+       /* chapter 9 and authentication (wireless) device states */
        USB_STATE_ATTACHED,
-       USB_STATE_POWERED,
+       USB_STATE_POWERED,                      /* wired */
+       USB_STATE_UNAUTHENTICATED,              /* auth */
+       USB_STATE_RECONNECTING,                 /* auth */
        USB_STATE_DEFAULT,                      /* limited function */
        USB_STATE_ADDRESS,
        USB_STATE_CONFIGURED,                   /* most functions */
index ce40675324bd5edb738c339bc56f61b01f1212bf..6f6c69777648f0f72f41a55fc1f79092a15092e1 100644 (file)
@@ -315,6 +315,7 @@ struct v4l2_pix_format
 #define V4L2_PIX_FMT_SN9C10X  v4l2_fourcc('S','9','1','0') /* SN9C10x compression */
 #define V4L2_PIX_FMT_PWC1     v4l2_fourcc('P','W','C','1') /* pwc older webcam */
 #define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P','W','C','2') /* pwc newer webcam */
+#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E','6','2','5') /* ET61X251 compression */
 
 /*
  *     F O R M A T   E N U M E R A T I O N
index df05f468fa5c312c028f45c9dc1ad81cbd1a2336..9a92aef8b0b29090696711728683d6caa8ac9942 100644 (file)
@@ -803,9 +803,9 @@ enum ieee80211_state {
 #define IEEE80211_24GHZ_MAX_CHANNEL 14
 #define IEEE80211_24GHZ_CHANNELS    14
 
-#define IEEE80211_52GHZ_MIN_CHANNEL 36
+#define IEEE80211_52GHZ_MIN_CHANNEL 34
 #define IEEE80211_52GHZ_MAX_CHANNEL 165
-#define IEEE80211_52GHZ_CHANNELS    32
+#define IEEE80211_52GHZ_CHANNELS    131
 
 enum {
        IEEE80211_CH_PASSIVE_ONLY = (1 << 0),
index e3e5436f8017929aeba0d271b7748d13c8a365b6..9c04f15090d2b6b6e75060ab56dfb69047ea5db7 100644 (file)
@@ -170,8 +170,8 @@ static inline int ip_route_connect(struct rtable **rp, u32 dst,
        return ip_route_output_flow(rp, &fl, sk, 0);
 }
 
-static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport,
-                                   struct sock *sk)
+static inline int ip_route_newports(struct rtable **rp, u8 protocol,
+                                   u16 sport, u16 dport, struct sock *sk)
 {
        if (sport != (*rp)->fl.fl_ip_sport ||
            dport != (*rp)->fl.fl_ip_dport) {
@@ -180,6 +180,7 @@ static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport,
                memcpy(&fl, &(*rp)->fl, sizeof(fl));
                fl.fl_ip_sport = sport;
                fl.fl_ip_dport = dport;
+               fl.proto = protocol;
                ip_rt_put(*rp);
                *rp = NULL;
                return ip_route_output_flow(rp, &fl, sk, 0);
index e94ca4d360358bb535224bca0766af0f706cef61..290e3b4d2aec040c46f1fc2f0ff8b9a8b3398472 100644 (file)
@@ -275,7 +275,7 @@ extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
                            int data_direction, void *buffer, unsigned bufflen,
                            struct scsi_sense_hdr *, int timeout, int retries);
 extern int scsi_execute_async(struct scsi_device *sdev,
-                             const unsigned char *cmd, int data_direction,
+                             const unsigned char *cmd, int cmd_len, int data_direction,
                              void *buffer, unsigned bufflen, int use_sg,
                              int timeout, int retries, void *privdata,
                              void (*done)(void *, char *, int, int),
index 467274a764d172487c2717f0aa7eac2eb5f81b0d..827992949c4bfe2b94635262483a4863aa0b2550 100644 (file)
@@ -554,7 +554,6 @@ struct Scsi_Host {
        /*
         * ordered write support
         */
-       unsigned ordered_flush:1;
        unsigned ordered_tag:1;
 
        /*
index 773219907dd8a96698f6c0390778538071e2e890..7712912dbc8488d54c7be1c73947a285005ba8a7 100644 (file)
@@ -114,16 +114,16 @@ rcu_torture_alloc(void)
 {
        struct list_head *p;
 
-       spin_lock(&rcu_torture_lock);
+       spin_lock_bh(&rcu_torture_lock);
        if (list_empty(&rcu_torture_freelist)) {
                atomic_inc(&n_rcu_torture_alloc_fail);
-               spin_unlock(&rcu_torture_lock);
+               spin_unlock_bh(&rcu_torture_lock);
                return NULL;
        }
        atomic_inc(&n_rcu_torture_alloc);
        p = rcu_torture_freelist.next;
        list_del_init(p);
-       spin_unlock(&rcu_torture_lock);
+       spin_unlock_bh(&rcu_torture_lock);
        return container_of(p, struct rcu_torture, rtort_free);
 }
 
@@ -134,9 +134,9 @@ static void
 rcu_torture_free(struct rcu_torture *p)
 {
        atomic_inc(&n_rcu_torture_free);
-       spin_lock(&rcu_torture_lock);
+       spin_lock_bh(&rcu_torture_lock);
        list_add_tail(&p->rtort_free, &rcu_torture_freelist);
-       spin_unlock(&rcu_torture_lock);
+       spin_unlock_bh(&rcu_torture_lock);
 }
 
 static void
index 3ee2ae45125f711bd52eb8635cf335cc9b15ffe9..ec7fd9cee30665e7626ec7d3fb92f9ee6bd57731 100644 (file)
@@ -5141,7 +5141,7 @@ static void init_sched_build_groups(struct sched_group groups[], cpumask_t span,
 #define SEARCH_SCOPE           2
 #define MIN_CACHE_SIZE         (64*1024U)
 #define DEFAULT_CACHE_SIZE     (5*1024*1024U)
-#define ITERATIONS             2
+#define ITERATIONS             1
 #define SIZE_THRESH            130
 #define COST_THRESH            130
 
@@ -5480,9 +5480,9 @@ static unsigned long long measure_migration_cost(int cpu1, int cpu2)
                                break;
                        }
                /*
-                * Increase the cachesize in 5% steps:
+                * Increase the cachesize in 10% steps:
                 */
-               size = size * 20 / 19;
+               size = size * 10 / 9;
        }
 
        if (migration_debug)
index 7477b1d2079e32a614ea82e6ae21fde3abe48373..1f23e683d6aa01da497a86a8cd5ac6804ef5d6fe 100644 (file)
@@ -155,7 +155,7 @@ int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
        static int firsttime = 1;
        int error = 0;
 
-       if (!timespec_valid(tv))
+       if (tv && !timespec_valid(tv))
                return -EINVAL;
 
        error = security_settime(tv, tz);
index 89e562feb1b10829ec3d689eb969f670868be686..d9deae43a9abbb0f8dfaeeb078e8fb83311bc481 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/bitops.h>
 #include <linux/key.h>
+#include <linux/interrupt.h>
 
 /*
  * UID task count cache, to get fast user lookup in "alloc_uid"
 
 static kmem_cache_t *uid_cachep;
 static struct list_head uidhash_table[UIDHASH_SZ];
+
+/*
+ * The uidhash_lock is mostly taken from process context, but it is
+ * occasionally also taken from softirq/tasklet context, when
+ * task-structs get RCU-freed. Hence all locking must be softirq-safe.
+ * But free_uid() is also called with local interrupts disabled, and running
+ * local_bh_enable() with local interrupts disabled is an error - we'll run
+ * softirq callbacks, and they can unconditionally enable interrupts, and
+ * the caller of free_uid() didn't expect that..
+ */
 static DEFINE_SPINLOCK(uidhash_lock);
 
 struct user_struct root_user = {
@@ -82,15 +93,19 @@ static inline struct user_struct *uid_hash_find(uid_t uid, struct list_head *has
 struct user_struct *find_user(uid_t uid)
 {
        struct user_struct *ret;
+       unsigned long flags;
 
-       spin_lock(&uidhash_lock);
+       spin_lock_irqsave(&uidhash_lock, flags);
        ret = uid_hash_find(uid, uidhashentry(uid));
-       spin_unlock(&uidhash_lock);
+       spin_unlock_irqrestore(&uidhash_lock, flags);
        return ret;
 }
 
 void free_uid(struct user_struct *up)
 {
+       unsigned long flags;
+
+       local_irq_save(flags);
        if (up && atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
                uid_hash_remove(up);
                key_put(up->uid_keyring);
@@ -98,6 +113,7 @@ void free_uid(struct user_struct *up)
                kmem_cache_free(uid_cachep, up);
                spin_unlock(&uidhash_lock);
        }
+       local_irq_restore(flags);
 }
 
 struct user_struct * alloc_uid(uid_t uid)
@@ -105,9 +121,9 @@ struct user_struct * alloc_uid(uid_t uid)
        struct list_head *hashent = uidhashentry(uid);
        struct user_struct *up;
 
-       spin_lock(&uidhash_lock);
+       spin_lock_irq(&uidhash_lock);
        up = uid_hash_find(uid, hashent);
-       spin_unlock(&uidhash_lock);
+       spin_unlock_irq(&uidhash_lock);
 
        if (!up) {
                struct user_struct *new;
@@ -137,7 +153,7 @@ struct user_struct * alloc_uid(uid_t uid)
                 * Before adding this, check whether we raced
                 * on adding the same user already..
                 */
-               spin_lock(&uidhash_lock);
+               spin_lock_irq(&uidhash_lock);
                up = uid_hash_find(uid, hashent);
                if (up) {
                        key_put(new->uid_keyring);
@@ -147,7 +163,7 @@ struct user_struct * alloc_uid(uid_t uid)
                        uid_hash_insert(new, hashent);
                        up = new;
                }
-               spin_unlock(&uidhash_lock);
+               spin_unlock_irq(&uidhash_lock);
 
        }
        return up;
@@ -183,9 +199,9 @@ static int __init uid_cache_init(void)
                INIT_LIST_HEAD(uidhash_table + n);
 
        /* Insert the root user immediately (init already runs as root) */
-       spin_lock(&uidhash_lock);
+       spin_lock_irq(&uidhash_lock);
        uid_hash_insert(&root_user, uidhashentry(0));
-       spin_unlock(&uidhash_lock);
+       spin_unlock_irq(&uidhash_lock);
 
        return 0;
 }
index ba442883e877fbda4808db858f215ac9c30334df..da687c8dc6ff013e62f04b535f2a26483e4db284 100644 (file)
@@ -104,6 +104,7 @@ static void destroy_nbp(struct net_bridge_port *p)
 {
        struct net_device *dev = p->dev;
 
+       dev->br_port = NULL;
        p->br = NULL;
        p->dev = NULL;
        dev_put(dev);
@@ -118,13 +119,24 @@ static void destroy_nbp_rcu(struct rcu_head *head)
        destroy_nbp(p);
 }
 
-/* called with RTNL */
+/* Delete port(interface) from bridge is done in two steps.
+ * via RCU. First step, marks device as down. That deletes
+ * all the timers and stops new packets from flowing through.
+ *
+ * Final cleanup doesn't occur until after all CPU's finished
+ * processing packets.
+ *
+ * Protected from multiple admin operations by RTNL mutex
+ */
 static void del_nbp(struct net_bridge_port *p)
 {
        struct net_bridge *br = p->br;
        struct net_device *dev = p->dev;
 
-       dev->br_port = NULL;
+       /* Race between RTNL notify and RCU callback */
+       if (p->deleted)
+               return;
+
        dev_set_promiscuity(dev, -1);
 
        cancel_delayed_work(&p->carrier_check);
@@ -132,16 +144,13 @@ static void del_nbp(struct net_bridge_port *p)
 
        spin_lock_bh(&br->lock);
        br_stp_disable_port(p);
+       p->deleted = 1;
        spin_unlock_bh(&br->lock);
 
        br_fdb_delete_by_port(br, p);
 
        list_del_rcu(&p->list);
 
-       del_timer_sync(&p->message_age_timer);
-       del_timer_sync(&p->forward_delay_timer);
-       del_timer_sync(&p->hold_timer);
-       
        call_rcu(&p->rcu, destroy_nbp_rcu);
 }
 
index c5bd631ffcd5793d67c29009151c380b6af03cac..e330b17b6d816620f2706fc4eab15c1f4ef21481 100644 (file)
@@ -68,6 +68,7 @@ struct net_bridge_port
        /* STP */
        u8                              priority;
        u8                              state;
+       u8                              deleted;
        u16                             port_no;
        unsigned char                   topology_change_ack;
        unsigned char                   config_pending;
index fd070a098f20656027dca9c38a3b7a43a0ad1082..ffb82073056e761267dcbd480603d01645cfd7cf 100644 (file)
@@ -2543,13 +2543,14 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
                case SIOCBONDENSLAVE:
                case SIOCBONDRELEASE:
                case SIOCBONDSETHWADDR:
-               case SIOCBONDSLAVEINFOQUERY:
-               case SIOCBONDINFOQUERY:
                case SIOCBONDCHANGEACTIVE:
                case SIOCBRADDIF:
                case SIOCBRDELIF:
                        if (!capable(CAP_NET_ADMIN))
                                return -EPERM;
+                       /* fall through */
+               case SIOCBONDSLAVEINFOQUERY:
+               case SIOCBONDINFOQUERY:
                        dev_load(ifr.ifr_name);
                        rtnl_lock();
                        ret = dev_ifsioc(&ifr, cmd);
index 9540946a48f35f9cbb89a0d82eacddcd2c4de3a3..93fbd01d225952c66228d228a66340101448166a 100644 (file)
@@ -64,7 +64,7 @@ static inline void *load_pointer(struct sk_buff *skb, int k,
 }
 
 /**
- *     sk_run_filter   -       run a filter on a socket
+ *     sk_run_filter - run a filter on a socket
  *     @skb: buffer to run the filter on
  *     @filter: filter to apply
  *     @flen: length of filter
@@ -78,8 +78,8 @@ unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int
 {
        struct sock_filter *fentry;     /* We walk down these */
        void *ptr;
-       u32 A = 0;                      /* Accumulator */
-       u32 X = 0;                      /* Index Register */
+       u32 A = 0;                      /* Accumulator */
+       u32 X = 0;                      /* Index Register */
        u32 mem[BPF_MEMWORDS];          /* Scratch Memory Store */
        u32 tmp;
        int k;
index d0732e9c8560e10d8ec239957fa3b8d4d3c1df00..6766f118f07068719b551644066839a154267cf7 100644 (file)
@@ -135,13 +135,15 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)
 struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
                            int fclone)
 {
+       kmem_cache_t *cache;
        struct skb_shared_info *shinfo;
        struct sk_buff *skb;
        u8 *data;
 
+       cache = fclone ? skbuff_fclone_cache : skbuff_head_cache;
+
        /* Get the HEAD */
-       skb = kmem_cache_alloc(fclone ? skbuff_fclone_cache : skbuff_head_cache,
-                               gfp_mask & ~__GFP_DMA);
+       skb = kmem_cache_alloc(cache, gfp_mask & ~__GFP_DMA);
        if (!skb)
                goto out;
 
@@ -180,7 +182,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
 out:
        return skb;
 nodata:
-       kmem_cache_free(skbuff_head_cache, skb);
+       kmem_cache_free(cache, skb);
        skb = NULL;
        goto out;
 }
index 00f983226672a6c70aca4a67368cceae2d7a118b..dc0487b5bacec375dda26bbdc4515b5a5cedc621 100644 (file)
@@ -119,7 +119,8 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        if (err != 0)
                goto failure;
 
-       err = ip_route_newports(&rt, inet->sport, inet->dport, sk);
+       err = ip_route_newports(&rt, IPPROTO_DCCP, inet->sport, inet->dport,
+                               sk);
        if (err != 0)
                goto failure;
 
index df074259f9c3100581f649499dac1ae5554d1770..80c4d048869e10e2880b5dff67ea22ccd1d0e8f6 100644 (file)
@@ -468,6 +468,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
 done:
         if (opt && opt != np->opt)
                sock_kfree_s(sk, opt, opt->tot_len);
+       dst_release(dst);
        return err;
 }
 
index 7a121802faa92d7aa33b07734d8c6a0f3165662e..960aa78cdb972e1662bde851d7b025c61502f0fe 100644 (file)
@@ -350,6 +350,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        u8 src[ETH_ALEN];
        struct ieee80211_crypt_data *crypt = NULL;
        int keyidx = 0;
+       int can_be_decrypted = 0;
 
        hdr = (struct ieee80211_hdr_4addr *)skb->data;
        stats = &ieee->stats;
@@ -410,12 +411,23 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                return 1;
        }
 
-       if (is_multicast_ether_addr(hdr->addr1)
-           ? ieee->host_mc_decrypt : ieee->host_decrypt) {
+       can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) ||
+                           is_broadcast_ether_addr(hdr->addr2)) ?
+           ieee->host_mc_decrypt : ieee->host_decrypt;
+
+       if (can_be_decrypted) {
                int idx = 0;
-               if (skb->len >= hdrlen + 3)
+               if (skb->len >= hdrlen + 3) {
+                       /* Top two-bits of byte 3 are the key index */
                        idx = skb->data[hdrlen + 3] >> 6;
+               }
+
+               /* ieee->crypt[] is WEP_KEY (4) in length.  Given that idx
+                * is only allowed 2-bits of storage, no value of idx can
+                * be provided via above code that would result in idx
+                * being out of range */
                crypt = ieee->crypt[idx];
+
 #ifdef NOT_YET
                sta = NULL;
 
@@ -553,7 +565,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
 
        /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
 
-       if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+       if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
            (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0)
                goto rx_dropped;
 
@@ -617,7 +629,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
 
        /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
         * encrypted/authenticated */
-       if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
+       if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
            ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
                goto rx_dropped;
 
@@ -1439,7 +1451,7 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                break;
 
        case IEEE80211_STYPE_PROBE_REQ:
-               IEEE80211_DEBUG_MGMT("recieved auth (%d)\n",
+               IEEE80211_DEBUG_MGMT("received auth (%d)\n",
                                     WLAN_FC_GET_STYPE(le16_to_cpu
                                                       (header->frame_ctl)));
 
@@ -1473,7 +1485,7 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
                break;
        case IEEE80211_STYPE_AUTH:
 
-               IEEE80211_DEBUG_MGMT("recieved auth (%d)\n",
+               IEEE80211_DEBUG_MGMT("received auth (%d)\n",
                                     WLAN_FC_GET_STYPE(le16_to_cpu
                                                       (header->frame_ctl)));
 
index 23e1630f50b7cf872e01286c01a108cbc66c478f..f87c6b89f8450e513fd6c434864e7ae65b267ad0 100644 (file)
@@ -232,15 +232,18 @@ static char *ipw2100_translate_scan(struct ieee80211_device *ieee,
        return start;
 }
 
+#define SCAN_ITEM_SIZE 128
+
 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
                          struct iw_request_info *info,
                          union iwreq_data *wrqu, char *extra)
 {
        struct ieee80211_network *network;
        unsigned long flags;
+       int err = 0;
 
        char *ev = extra;
-       char *stop = ev + IW_SCAN_MAX_DATA;
+       char *stop = ev + wrqu->data.length;
        int i = 0;
 
        IEEE80211_DEBUG_WX("Getting scan\n");
@@ -249,6 +252,11 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
 
        list_for_each_entry(network, &ieee->network_list, list) {
                i++;
+               if (stop - ev < SCAN_ITEM_SIZE) {
+                       err = -E2BIG;
+                       break;
+               }
+
                if (ieee->scan_age == 0 ||
                    time_after(network->last_scanned + ieee->scan_age, jiffies))
                        ev = ipw2100_translate_scan(ieee, ev, stop, network);
@@ -270,7 +278,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
 
        IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
 
-       return 0;
+       return err;
 }
 
 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
index d8ce7133cd8f28ede0740ab682243e4f78f2bddb..0b4e95f93dad62cbfed26297ada2fbe86cf07163 100644 (file)
@@ -970,7 +970,7 @@ int igmp_rcv(struct sk_buff *skb)
        case IGMP_MTRACE_RESP:
                break;
        default:
-               NETDEBUG(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type);
+               break;
        }
 
 drop:
index 3284cfb993e6bd9c70963ba0f389b582f4183ab9..128de4d7c0b7dd40c95d94b3efdbab73a2e20041 100644 (file)
@@ -230,7 +230,6 @@ static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
                        if (tp->snd_cwnd < tp->snd_cwnd_clamp)
                                tp->snd_cwnd++;
                        tp->snd_cwnd_cnt = 0;
-                       ca->ccount++;
                }
        }
 }
index 6ea353907af5757de1abc84e6b87274afa4d26fe..233bdf2599658513c8ede17ebcc77c38bc2cac4a 100644 (file)
@@ -236,7 +236,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        if (err)
                goto failure;
 
-       err = ip_route_newports(&rt, inet->sport, inet->dport, sk);
+       err = ip_route_newports(&rt, IPPROTO_TCP, inet->sport, inet->dport, sk);
        if (err)
                goto failure;
 
@@ -1845,7 +1845,6 @@ void __init tcp_v4_init(struct net_proto_family *ops)
 }
 
 EXPORT_SYMBOL(ipv4_specific);
-EXPORT_SYMBOL(inet_bind_bucket_create);
 EXPORT_SYMBOL(tcp_hashinfo);
 EXPORT_SYMBOL(tcp_prot);
 EXPORT_SYMBOL(tcp_unhash);
index 6c05c7978bef2cf469111dfd891c5052a587dfac..4420948a1bfe9f23ec29de602551dd6bca9cbcf3 100644 (file)
@@ -1252,8 +1252,7 @@ int igmp6_event_query(struct sk_buff *skb)
                }
        } else {
                for (ma = idev->mc_list; ma; ma=ma->next) {
-                       if (group_type != IPV6_ADDR_ANY &&
-                           !ipv6_addr_equal(group, &ma->mca_addr))
+                       if (!ipv6_addr_equal(group, &ma->mca_addr))
                                continue;
                        spin_lock_bh(&ma->mca_lock);
                        if (ma->mca_flags & MAF_TIMER_RUNNING) {
@@ -1268,11 +1267,10 @@ int igmp6_event_query(struct sk_buff *skb)
                                        ma->mca_flags &= ~MAF_GSQUERY;
                        }
                        if (!(ma->mca_flags & MAF_GSQUERY) ||
-                          mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs))
+                           mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs))
                                igmp6_group_queried(ma, max_delay);
                        spin_unlock_bh(&ma->mca_lock);
-                       if (group_type != IPV6_ADDR_ANY)
-                               break;
+                       break;
                }
        }
        read_unlock_bh(&idev->lock);
@@ -1351,7 +1349,7 @@ static int is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type,
                         * in all filters
                         */
                        if (psf->sf_count[MCAST_INCLUDE])
-                               return 0;
+                               return type == MLD2_MODE_IS_INCLUDE;
                        return pmc->mca_sfcount[MCAST_EXCLUDE] ==
                                psf->sf_count[MCAST_EXCLUDE];
                }
@@ -1966,7 +1964,7 @@ static void sf_markstate(struct ifmcaddr6 *pmc)
 
 static int sf_setstate(struct ifmcaddr6 *pmc)
 {
-       struct ip6_sf_list *psf;
+       struct ip6_sf_list *psf, *dpsf;
        int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE];
        int qrv = pmc->idev->mc_qrv;
        int new_in, rv;
@@ -1978,8 +1976,48 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
                                !psf->sf_count[MCAST_INCLUDE];
                } else
                        new_in = psf->sf_count[MCAST_INCLUDE] != 0;
-               if (new_in != psf->sf_oldin) {
-                       psf->sf_crcount = qrv;
+               if (new_in) {
+                       if (!psf->sf_oldin) {
+                               struct ip6_sf_list *prev = 0;
+
+                               for (dpsf=pmc->mca_tomb; dpsf;
+                                    dpsf=dpsf->sf_next) {
+                                       if (ipv6_addr_equal(&dpsf->sf_addr,
+                                           &psf->sf_addr))
+                                               break;
+                                       prev = dpsf;
+                               }
+                               if (dpsf) {
+                                       if (prev)
+                                               prev->sf_next = dpsf->sf_next;
+                                       else
+                                               pmc->mca_tomb = dpsf->sf_next;
+                                       kfree(dpsf);
+                               }
+                               psf->sf_crcount = qrv;
+                               rv++;
+                       }
+               } else if (psf->sf_oldin) {
+                       psf->sf_crcount = 0;
+                       /*
+                        * add or update "delete" records if an active filter
+                        * is now inactive
+                        */
+                       for (dpsf=pmc->mca_tomb; dpsf; dpsf=dpsf->sf_next)
+                               if (ipv6_addr_equal(&dpsf->sf_addr,
+                                   &psf->sf_addr))
+                                       break;
+                       if (!dpsf) {
+                               dpsf = (struct ip6_sf_list *)
+                                       kmalloc(sizeof(*dpsf), GFP_ATOMIC);
+                               if (!dpsf)
+                                       continue;
+                               *dpsf = *psf;
+                               /* pmc->mca_lock held by callers */
+                               dpsf->sf_next = pmc->mca_tomb;
+                               pmc->mca_tomb = dpsf;
+                       }
+                       dpsf->sf_crcount = qrv;
                        rv++;
                }
        }
index 66d04004afdaec2a731d953752fb970f17121112..ca9cf6853755fc3081693334c6f8f3e70265dcac 100644 (file)
@@ -515,6 +515,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
 done:
         if (opt && opt != np->opt)
                sock_kfree_s(sk, opt, opt->tot_len);
+       dst_release(dst);
        return err;
 }
 
index 43f1ce74187d524122d8fbf6d325c7395dfb534d..ae86d237a4569b47e764db78ebe359390bc63359 100644 (file)
@@ -1620,6 +1620,7 @@ static int key_notify_sa_flush(struct km_event *c)
                return -ENOBUFS;
        hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
        hdr->sadb_msg_satype = pfkey_proto2satype(c->data.proto);
+       hdr->sadb_msg_type = SADB_FLUSH;
        hdr->sadb_msg_seq = c->seq;
        hdr->sadb_msg_pid = c->pid;
        hdr->sadb_msg_version = PF_KEY_V2;
@@ -2385,6 +2386,7 @@ static int key_notify_policy_flush(struct km_event *c)
        if (!skb_out)
                return -ENOBUFS;
        hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
+       hdr->sadb_msg_type = SADB_X_SPDFLUSH;
        hdr->sadb_msg_seq = c->seq;
        hdr->sadb_msg_pid = c->pid;
        hdr->sadb_msg_version = PF_KEY_V2;
index ee93abc71cb8aaefde9f24bbd6a5e5326fc5aee3..9db7dbdb16e6bd14c7ca23dc6c8dfe11e16f4566 100644 (file)
@@ -365,7 +365,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
         */
         
        err = -EMSGSIZE;
-       if(len>dev->mtu+dev->hard_header_len)
+       if (len > dev->mtu + dev->hard_header_len)
                goto out_unlock;
 
        err = -ENOBUFS;
@@ -935,7 +935,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add
         *      Check legality
         */
         
-       if(addr_len!=sizeof(struct sockaddr))
+       if (addr_len != sizeof(struct sockaddr))
                return -EINVAL;
        strlcpy(name,uaddr->sa_data,sizeof(name));
 
@@ -1092,7 +1092,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
         *      retries.
         */
 
-       if(skb==NULL)
+       if (skb == NULL)
                goto out;
 
        /*
@@ -1392,8 +1392,8 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
        if (level != SOL_PACKET)
                return -ENOPROTOOPT;
 
-       if (get_user(len,optlen))
-               return -EFAULT;
+       if (get_user(len, optlen))
+               return -EFAULT;
 
        if (len < 0)
                return -EINVAL;
@@ -1419,9 +1419,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
                return -ENOPROTOOPT;
        }
 
-       if (put_user(len, optlen))
-               return -EFAULT;
-       return 0;
+       if (put_user(len, optlen))
+               return -EFAULT;
+       return 0;
 }
 
 
index 71c9a961c321a13e6b68e837cc47652e27a4e437..2b9a832b29a70bdbb46d0ce401d680c9a0121654 100644 (file)
@@ -884,7 +884,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
 {
        struct sctp_transport *transport = (struct sctp_transport *) arg;
 
-       if (asoc->overall_error_count > asoc->max_retrans) {
+       if (asoc->overall_error_count >= asoc->max_retrans) {
                /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_U32(SCTP_ERROR_NO_ERROR));
@@ -2122,7 +2122,7 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
        struct sctp_bind_addr *bp;
        int attempts = asoc->init_err_counter + 1;
 
-       if (attempts >= asoc->max_init_attempts) {
+       if (attempts > asoc->max_init_attempts) {
                sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
                                SCTP_U32(SCTP_ERROR_STALE_COOKIE));
                return SCTP_DISPOSITION_DELETE_TCB;
@@ -4640,7 +4640,7 @@ sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep,
 
        SCTP_DEBUG_PRINTK("Timer T1 expired (INIT).\n");
 
-       if (attempts < asoc->max_init_attempts) {
+       if (attempts <= asoc->max_init_attempts) {
                bp = (struct sctp_bind_addr *) &asoc->base.bind_addr;
                repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0);
                if (!repl)
@@ -4697,7 +4697,7 @@ sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep
 
        SCTP_DEBUG_PRINTK("Timer T1 expired (COOKIE-ECHO).\n");
 
-       if (attempts < asoc->max_init_attempts) {
+       if (attempts <= asoc->max_init_attempts) {
                repl = sctp_make_cookie_echo(asoc, NULL);
                if (!repl)
                        return SCTP_DISPOSITION_NOMEM;
index fb1821d9f33809e5ace99b572cbbf813aea8d0ca..0ea947eb681320561d3e3d61ac91001aa1043926 100644 (file)
@@ -5426,7 +5426,7 @@ out:
        return err;
 
 do_error:
-       if (asoc->init_err_counter + 1 >= asoc->max_init_attempts)
+       if (asoc->init_err_counter + 1 > asoc->max_init_attempts)
                err = -ETIMEDOUT;
        else
                err = -ECONNREFUSED;
index 1caac0164643c202a55c1e8394b9669706723591..8529ea6f7aa83437174727478988702d4e9db89b 100644 (file)
@@ -368,8 +368,8 @@ static int seclvl_capable(struct task_struct *tsk, int cap)
  */
 static int seclvl_settime(struct timespec *tv, struct timezone *tz)
 {
-       struct timespec now;
-       if (seclvl > 1) {
+       if (tv && seclvl > 1) {
+               struct timespec now;
                now = current_kernel_time();
                if (tv->tv_sec < now.tv_sec ||
                    (tv->tv_sec == now.tv_sec && tv->tv_nsec < now.tv_nsec)) {
index b963c550dae6b50f069ffd52e38ece70b7360ba7..bdee0502f3e232e32cc2e70c90349ae2ae21e8e8 100644 (file)
@@ -462,7 +462,7 @@ stop_dac(struct au1550_state *s)
        /* Wait for Transmit Busy to show disabled.
        */
        do {
-               stat = readl((void *)PSC_AC97STAT);
+               stat = au_readl(PSC_AC97STAT);
                au_sync();
        } while ((stat & PSC_AC97STAT_TB) != 0);
 
@@ -491,7 +491,7 @@ stop_adc(struct au1550_state *s)
        /* Wait for Receive Busy to show disabled.
        */
        do {
-               stat = readl((void *)PSC_AC97STAT);
+               stat = au_readl(PSC_AC97STAT);
                au_sync();
        } while ((stat & PSC_AC97STAT_RB) != 0);
 
@@ -541,7 +541,7 @@ set_xmit_slots(int num_channels)
        /* Wait for Device ready.
        */
        do {
-               stat = readl((void *)PSC_AC97STAT);
+               stat = au_readl(PSC_AC97STAT);
                au_sync();
        } while ((stat & PSC_AC97STAT_DR) == 0);
 }
@@ -573,7 +573,7 @@ set_recv_slots(int num_channels)
        /* Wait for Device ready.
        */
        do {
-               stat = readl((void *)PSC_AC97STAT);
+               stat = au_readl(PSC_AC97STAT);
                au_sync();
        } while ((stat & PSC_AC97STAT_DR) == 0);
 }
@@ -1995,7 +1995,7 @@ au1550_probe(void)
        /* Wait for PSC ready.
        */
        do {
-               val = readl((void *)PSC_AC97STAT);
+               val = au_readl(PSC_AC97STAT);
                au_sync();
        } while ((val & PSC_AC97STAT_SR) == 0);
 
@@ -2018,7 +2018,7 @@ au1550_probe(void)
        /* Wait for Device ready.
        */
        do {
-               val = readl((void *)PSC_AC97STAT);
+               val = au_readl(PSC_AC97STAT);
                au_sync();
        } while ((val & PSC_AC97STAT_DR) == 0);